QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsprocessingdxflayerswidgetwrapper.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingdxflayerswidgetwrapper.cpp
3 ---------------------
4 Date : September 2020
5 Copyright : (C) 2020 by Alexander Bruy
6 Email : alexander dot bruy at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgspanelwidget.h"
22
23#include <QBoxLayout>
24#include <QLineEdit>
25#include <QMessageBox>
26#include <QPushButton>
27#include <QStandardItemModel>
28#include <QToolButton>
29
30#include "moc_qgsprocessingdxflayerswidgetwrapper.cpp"
31
33
34//
35// QgsProcessingDxfLayerDetailsWidget
36//
37
38QgsProcessingDxfLayerDetailsWidget::QgsProcessingDxfLayerDetailsWidget( const QVariant &value, QgsProject *project )
39{
40 setupUi( this );
41
42 mFieldsComboBox->setAllowEmptyFieldName( true );
43
44 mContext.setProject( project );
45
47 mLayer = layer.layer();
48
49 if ( !mLayer )
50 return;
51
52 mFieldsComboBox->setLayer( mLayer );
53
54 if ( mLayer->fields().exists( layer.layerOutputAttributeIndex() ) )
55 mFieldsComboBox->setField( mLayer->fields().at( layer.layerOutputAttributeIndex() ).name() );
56
57 mOverriddenName->setText( layer.overriddenName() );
58
59 if ( mLayer->geometryType() == Qgis::GeometryType::Point )
60 {
61 // Data defined blocks are only available for point layers
62 mGroupBoxBlocks->setVisible( true );
63 mGroupBoxBlocks->setChecked( layer.buildDataDefinedBlocks() );
64 mSpinBoxBlocks->setValue( layer.dataDefinedBlocksMaximumNumberOfClasses() );
65 }
66 else
67 {
68 mGroupBoxBlocks->setVisible( false );
69 }
70
71 connect( mFieldsComboBox, &QgsFieldComboBox::fieldChanged, this, &QgsPanelWidget::widgetChanged );
72 connect( mOverriddenName, &QLineEdit::textChanged, this, &QgsPanelWidget::widgetChanged );
73 connect( mGroupBoxBlocks, &QGroupBox::toggled, this, &QgsPanelWidget::widgetChanged );
74 connect( mSpinBoxBlocks, &QSpinBox::textChanged, this, &QgsPanelWidget::widgetChanged );
75}
76
77QVariant QgsProcessingDxfLayerDetailsWidget::value() const
78{
79 const int index = mLayer->fields().lookupField( mFieldsComboBox->currentField() );
80 const QgsDxfExport::DxfLayer layer( mLayer, index, mGroupBoxBlocks->isChecked(), mSpinBoxBlocks->value(), mOverriddenName->text().trimmed() );
82}
83
84
85//
86// QgsProcessingDxfLayersPanelWidget
87//
88
89QgsProcessingDxfLayersPanelWidget::QgsProcessingDxfLayersPanelWidget(
90 const QVariant &value,
91 QgsProject *project,
92 QWidget *parent
93)
94 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
95 , mProject( project )
96{
97 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
98
99 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Layer…" ) );
100 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
101 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
102
103 // populate the list: first layers already selected, then layers from project not yet selected
104 mContext.setProject( project );
105
106 QSet<const QgsVectorLayer *> seenVectorLayers;
107 const QVariantList valueList = value.toList();
108 for ( const QVariant &v : valueList )
109 {
111 if ( !layer.layer() )
112 continue; // skip any invalid layers
113
114 addOption( v, titleForLayer( layer ), true );
115 seenVectorLayers.insert( layer.layer() );
116 }
117
118 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
119 for ( const QgsVectorLayer *layer : options )
120 {
121 if ( seenVectorLayers.contains( layer ) )
122 continue;
123
124 QVariantMap vm;
125 vm["layer"] = layer->id();
126 vm["attributeIndex"] = -1;
127 vm["overriddenLayerName"] = QString();
128 vm["buildDataDefinedBlocks"] = DEFAULT_DXF_DATA_DEFINED_BLOCKS;
129 vm["dataDefinedBlocksMaximumNumberOfClasses"] = -1;
130
131 const QString title = layer->name();
132 addOption( vm, title, false );
133 }
134}
135
136void QgsProcessingDxfLayersPanelWidget::configureLayer()
137{
138 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
139 if ( selection.size() != 1 )
140 {
141 QMessageBox::warning( this, tr( "Configure Layer" ), tr( "Please select a single layer." ) );
142 return;
143 }
144
145 QStandardItem *item = mModel->itemFromIndex( selection[0] );
146 const QVariant value = item->data( Qt::UserRole );
147
149 if ( panel && panel->dockMode() )
150 {
151 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
152 widget->setPanelTitle( tr( "Configure Layer" ) );
153 widget->buttonBox()->hide();
154
155 connect( widget, &QgsProcessingDxfLayerDetailsWidget::widgetChanged, this, [this, item, widget]() {
156 setItemValue( item, widget->value() );
157 } );
158 panel->openPanel( widget );
159 }
160 else
161 {
162 QDialog dlg;
163 dlg.setWindowTitle( tr( "Configure Layer" ) );
164 QVBoxLayout *vLayout = new QVBoxLayout();
165 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
166 vLayout->addWidget( widget );
167 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
168 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
169 dlg.setLayout( vLayout );
170 if ( dlg.exec() )
171 {
172 setItemValue( item, widget->value() );
173 }
174 }
175}
176
177void QgsProcessingDxfLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
178{
179 mContext.setProject( mProject );
180
181 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( value.toMap(), mContext );
182
183 item->setText( titleForLayer( layer ) );
184 item->setData( value, Qt::UserRole );
185}
186
187QString QgsProcessingDxfLayersPanelWidget::titleForLayer( const QgsDxfExport::DxfLayer &layer )
188{
189 QString title = layer.layer()->name();
190
191 // if both options are set, the split attribute takes precedence,
192 // so hide overridden message to give users a hint on the result.
193 if ( layer.layerOutputAttributeIndex() != -1 )
194 {
195 title += tr( " [split attribute: %1]" ).arg( layer.splitLayerAttribute() );
196 }
197 else
198 {
199 if ( !layer.overriddenName().isEmpty() )
200 {
201 title += tr( " [overridden name: %1]" ).arg( layer.overriddenName() );
202 }
203 }
204
205 return title;
206}
207
208
209//
210// QgsProcessingDxfLayersWidget
211//
212
213QgsProcessingDxfLayersWidget::QgsProcessingDxfLayersWidget( QWidget *parent )
214 : QWidget( parent )
215{
216 QHBoxLayout *hl = new QHBoxLayout();
217 hl->setContentsMargins( 0, 0, 0, 0 );
218
219 mLineEdit = new QLineEdit();
220 mLineEdit->setEnabled( false );
221 hl->addWidget( mLineEdit, 1 );
222
223 mToolButton = new QToolButton();
224 mToolButton->setText( QString( QChar( 0x2026 ) ) );
225 hl->addWidget( mToolButton );
226
227 setLayout( hl );
228
229 updateSummaryText();
230
231 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingDxfLayersWidget::showDialog );
232}
233
234void QgsProcessingDxfLayersWidget::setValue( const QVariant &value )
235{
236 if ( value.isValid() )
237 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
238 else
239 mValue.clear();
240
241 updateSummaryText();
242 emit changed();
243}
244
245void QgsProcessingDxfLayersWidget::setProject( QgsProject *project )
246{
247 mProject = project;
248}
249
250void QgsProcessingDxfLayersWidget::showDialog()
251{
253 if ( panel && panel->dockMode() )
254 {
255 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
256 widget->setPanelTitle( tr( "Input layers" ) );
257 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
258 setValue( widget->selectedOptions() );
259 } );
260 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
261 panel->openPanel( widget );
262 }
263 else
264 {
265 QDialog dlg;
266 dlg.setWindowTitle( tr( "Input layers" ) );
267 QVBoxLayout *vLayout = new QVBoxLayout();
268 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
269 vLayout->addWidget( widget );
270 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
271 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
272 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
273 dlg.setLayout( vLayout );
274 if ( dlg.exec() )
275 {
276 setValue( widget->selectedOptions() );
277 }
278 }
279}
280
281void QgsProcessingDxfLayersWidget::updateSummaryText()
282{
283 mLineEdit->setText( tr( "%n vector layer(s) selected", nullptr, mValue.count() ) );
284}
285
286
287//
288// QgsProcessingDxfLayersWidgetWrapper
289//
290
291QgsProcessingDxfLayersWidgetWrapper::QgsProcessingDxfLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
292 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
293{
294}
295
296QString QgsProcessingDxfLayersWidgetWrapper::parameterType() const
297{
299}
300
301QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDxfLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
302{
303 return new QgsProcessingDxfLayersWidgetWrapper( parameter, type );
304}
305
306QWidget *QgsProcessingDxfLayersWidgetWrapper::createWidget()
307{
308 mPanel = new QgsProcessingDxfLayersWidget( nullptr );
309 mPanel->setProject( widgetContext().project() );
310 connect( mPanel, &QgsProcessingDxfLayersWidget::changed, this, [this] {
311 emit widgetValueHasChanged( this );
312 } );
313 return mPanel;
314}
315
316void QgsProcessingDxfLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
317{
319 if ( mPanel )
320 {
321 mPanel->setProject( context.project() );
322 }
323}
324
325void QgsProcessingDxfLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
326{
327 Q_UNUSED( context )
328 if ( mPanel )
329 {
330 mPanel->setValue( value );
331 }
332}
333
334QVariant QgsProcessingDxfLayersWidgetWrapper::widgetValue() const
335{
336 return mPanel ? mPanel->value() : QVariant();
337}
338
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3533
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3671
@ Point
Points.
Definition qgis.h:359
A widget wrapper for Processing parameter value widgets.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QString name
Definition qgsmaplayer.h:84
Base class for any widget that can be shown as an inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
void widgetChanged()
Emitted when the widget state changes.
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
Contains information about the context in which a processing algorithm is executed.
Base class for the definition of processing parameters.
static QVariantMap layerAsVariantMap(const QgsDxfExport::DxfLayer &layer)
Converts a single input layer to QVariant representation (a QVariantMap).
static QgsDxfExport::DxfLayer variantMapAsLayer(const QVariantMap &layerVariantMap, QgsProcessingContext &context)
Converts a QVariant value (a QVariantMap) to a single input layer.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown.
QgsProject * project() const
Returns the project associated with the widget.
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.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
Represents a vector layer which manages a vector based dataset.
Layers and optional attribute index to split into multiple layers using attribute value as layer name...
QString overriddenName() const
Returns the overridden layer name to be used in the exported DXF.
bool buildDataDefinedBlocks() const
Flag if data defined point block symbols should be created.
QgsVectorLayer * layer() const
Returns the layer.
int dataDefinedBlocksMaximumNumberOfClasses() const
Returns the maximum number of data defined symbol classes for which blocks are created.
QString splitLayerAttribute() const
If the split layer attribute is set, the vector layer will be split into several dxf layers,...
int layerOutputAttributeIndex() const
Returns the attribute index used to split into multiple layers.