QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
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 <QBoxLayout>
19#include <QLineEdit>
20#include <QMessageBox>
21#include <QPushButton>
22#include <QStandardItemModel>
23#include <QToolButton>
24
25#include "qgspanelwidget.h"
29
31
32//
33// QgsProcessingDxfLayerDetailsWidget
34//
35
36QgsProcessingDxfLayerDetailsWidget::QgsProcessingDxfLayerDetailsWidget( const QVariant &value, QgsProject *project )
37{
38 setupUi( this );
39
40 mFieldsComboBox->setAllowEmptyFieldName( true );
41
42 mContext.setProject( project );
43
45 mLayer = layer.layer();
46
47 if ( !mLayer )
48 return;
49
50 mFieldsComboBox->setLayer( mLayer );
51
52 if ( mLayer->fields().exists( layer.layerOutputAttributeIndex() ) )
53 mFieldsComboBox->setField( mLayer->fields().at( layer.layerOutputAttributeIndex() ).name() );
54
55 mOverriddenName->setText( layer.overriddenName() );
56
57 if ( mLayer->geometryType() == Qgis::GeometryType::Point )
58 {
59 // Data defined blocks are only available for point layers
60 mGroupBoxBlocks->setVisible( true );
61 mGroupBoxBlocks->setChecked( layer.buildDataDefinedBlocks() );
62 mSpinBoxBlocks->setValue( layer.dataDefinedBlocksMaximumNumberOfClasses() );
63 }
64 else
65 {
66 mGroupBoxBlocks->setVisible( false );
67 }
68
69 connect( mFieldsComboBox, &QgsFieldComboBox::fieldChanged, this, &QgsPanelWidget::widgetChanged );
70 connect( mOverriddenName, &QLineEdit::textChanged, this, &QgsPanelWidget::widgetChanged );
71 connect( mGroupBoxBlocks, &QGroupBox::toggled, this, &QgsPanelWidget::widgetChanged );
72 connect( mSpinBoxBlocks, &QSpinBox::textChanged, this, &QgsPanelWidget::widgetChanged );
73}
74
75QVariant QgsProcessingDxfLayerDetailsWidget::value() const
76{
77 const int index = mLayer->fields().lookupField( mFieldsComboBox->currentField() );
78 const QgsDxfExport::DxfLayer layer( mLayer, index, mGroupBoxBlocks->isChecked(), mSpinBoxBlocks->value(), mOverriddenName->text().trimmed() );
80}
81
82
83//
84// QgsProcessingDxfLayersPanelWidget
85//
86
87QgsProcessingDxfLayersPanelWidget::QgsProcessingDxfLayersPanelWidget(
88 const QVariant &value,
89 QgsProject *project,
90 QWidget *parent )
91 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
92 , mProject( project )
93{
94 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
95
96 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Layer…" ) );
97 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
98 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
99
100 // populate the list: first layers already selected, then layers from project not yet selected
101 mContext.setProject( project );
102
103 QSet<const QgsVectorLayer *> seenVectorLayers;
104 const QVariantList valueList = value.toList();
105 for ( const QVariant &v : valueList )
106 {
108 if ( !layer.layer() )
109 continue; // skip any invalid layers
110
111 addOption( v, titleForLayer( layer ), true );
112 seenVectorLayers.insert( layer.layer() );
113 }
114
115 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList< int >() << static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
116 for ( const QgsVectorLayer *layer : options )
117 {
118 if ( seenVectorLayers.contains( layer ) )
119 continue;
120
121 QVariantMap vm;
122 vm["layer"] = layer->id();
123 vm["attributeIndex"] = -1;
124 vm["overriddenLayerName"] = QString();
125 vm["buildDataDefinedBlocks"] = DEFAULT_DXF_DATA_DEFINED_BLOCKS;
126 vm["dataDefinedBlocksMaximumNumberOfClasses"] = -1;
127
128 const QString title = layer->name();
129 addOption( vm, title, false );
130 }
131}
132
133void QgsProcessingDxfLayersPanelWidget::configureLayer()
134{
135 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
136 if ( selection.size() != 1 )
137 {
138 QMessageBox::warning( this, tr( "Configure Layer" ), tr( "Please select a single layer." ) );
139 return;
140 }
141
142 QStandardItem *item = mModel->itemFromIndex( selection[0] );
143 const QVariant value = item->data( Qt::UserRole );
144
146 if ( panel && panel->dockMode() )
147 {
148 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
149 widget->setPanelTitle( tr( "Configure Layer" ) );
150 widget->buttonBox()->hide();
151
152 connect( widget, &QgsProcessingDxfLayerDetailsWidget::widgetChanged, this, [ = ]()
153 {
154 setItemValue( item, widget->value() );
155 } );
156 panel->openPanel( widget );
157 }
158 else
159 {
160 QDialog dlg;
161 dlg.setWindowTitle( tr( "Configure Layer" ) );
162 QVBoxLayout *vLayout = new QVBoxLayout();
163 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
164 vLayout->addWidget( widget );
165 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
166 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
167 dlg.setLayout( vLayout );
168 if ( dlg.exec() )
169 {
170 setItemValue( item, widget->value() );
171 }
172 }
173}
174
175void QgsProcessingDxfLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
176{
177 mContext.setProject( mProject );
178
179 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( value.toMap(), mContext );
180
181 item->setText( titleForLayer( layer ) );
182 item->setData( value, Qt::UserRole );
183}
184
185QString QgsProcessingDxfLayersPanelWidget::titleForLayer( const QgsDxfExport::DxfLayer &layer )
186{
187 QString title = layer.layer()->name();
188
189 // if both options are set, the split attribute takes precedence,
190 // so hide overridden message to give users a hint on the result.
191 if ( layer.layerOutputAttributeIndex() != -1 )
192 {
193 title += tr( " [split attribute: %1]" ).arg( layer.splitLayerAttribute() );
194 }
195 else
196 {
197 if ( !layer.overriddenName().isEmpty() )
198 {
199 title += tr( " [overridden name: %1]" ).arg( layer.overriddenName() );
200 }
201 }
202
203 return title;
204}
205
206
207//
208// QgsProcessingDxfLayersWidget
209//
210
211QgsProcessingDxfLayersWidget::QgsProcessingDxfLayersWidget( QWidget *parent )
212 : QWidget( parent )
213{
214 QHBoxLayout *hl = new QHBoxLayout();
215 hl->setContentsMargins( 0, 0, 0, 0 );
216
217 mLineEdit = new QLineEdit();
218 mLineEdit->setEnabled( false );
219 hl->addWidget( mLineEdit, 1 );
220
221 mToolButton = new QToolButton();
222 mToolButton->setText( QString( QChar( 0x2026 ) ) );
223 hl->addWidget( mToolButton );
224
225 setLayout( hl );
226
227 updateSummaryText();
228
229 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingDxfLayersWidget::showDialog );
230}
231
232void QgsProcessingDxfLayersWidget::setValue( const QVariant &value )
233{
234 if ( value.isValid() )
235 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
236 else
237 mValue.clear();
238
239 updateSummaryText();
240 emit changed();
241}
242
243void QgsProcessingDxfLayersWidget::setProject( QgsProject *project )
244{
245 mProject = project;
246}
247
248void QgsProcessingDxfLayersWidget::showDialog()
249{
251 if ( panel && panel->dockMode() )
252 {
253 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
254 widget->setPanelTitle( tr( "Input layers" ) );
255 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
256 {
257 setValue( widget->selectedOptions() );
258 } );
259 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
260 panel->openPanel( widget );
261 }
262 else
263 {
264 QDialog dlg;
265 dlg.setWindowTitle( tr( "Input layers" ) );
266 QVBoxLayout *vLayout = new QVBoxLayout();
267 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
268 vLayout->addWidget( widget );
269 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
270 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
271 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
272 dlg.setLayout( vLayout );
273 if ( dlg.exec() )
274 {
275 setValue( widget->selectedOptions() );
276 }
277 }
278}
279
280void QgsProcessingDxfLayersWidget::updateSummaryText()
281{
282 mLineEdit->setText( tr( "%n vector layer(s) selected", nullptr, mValue.count() ) );
283}
284
285
286//
287// QgsProcessingDxfLayersWidgetWrapper
288//
289
290QgsProcessingDxfLayersWidgetWrapper::QgsProcessingDxfLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
291 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
292{
293}
294
295QString QgsProcessingDxfLayersWidgetWrapper::parameterType() const
296{
298}
299
300QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDxfLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
301{
302 return new QgsProcessingDxfLayersWidgetWrapper( parameter, type );
303}
304
305QWidget *QgsProcessingDxfLayersWidgetWrapper::createWidget()
306{
307 mPanel = new QgsProcessingDxfLayersWidget( nullptr );
308 mPanel->setProject( widgetContext().project() );
309 connect( mPanel, &QgsProcessingDxfLayersWidget::changed, this, [ = ]
310 {
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
339QStringList QgsProcessingDxfLayersWidgetWrapper::compatibleParameterTypes() const
340{
341 return QStringList()
348}
349
350QStringList QgsProcessingDxfLayersWidgetWrapper::compatibleOutputTypes() const
351{
352 return QStringList()
358}
359
@ VectorAnyGeometry
Any vector layer with geometry.
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:80
Base class for any widget that can be shown as a 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 ...
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.
bool dockMode()
Returns the dock mode state.
Contains information about the context in which a processing algorithm is executed.
WidgetType
Types of dialogs which Processing widgets can be created for.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
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.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
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:107
Represents a vector layer which manages a vector based data sets.
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.