QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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( const QVariant &value, QgsProject *project, QWidget *parent )
90 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
91 , mProject( project )
92{
93 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
94
95 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Layer…" ) );
96 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
97 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
98
99 // populate the list: first layers already selected, then layers from project not yet selected
100 mContext.setProject( project );
101
102 QSet<const QgsVectorLayer *> seenVectorLayers;
103 const QVariantList valueList = value.toList();
104 for ( const QVariant &v : valueList )
105 {
107 if ( !layer.layer() )
108 continue; // skip any invalid layers
109
110 addOption( v, titleForLayer( layer ), true );
111 seenVectorLayers.insert( layer.layer() );
112 }
113
114 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
115 for ( const QgsVectorLayer *layer : options )
116 {
117 if ( seenVectorLayers.contains( layer ) )
118 continue;
119
120 QVariantMap vm;
121 vm["layer"] = layer->id();
122 vm["attributeIndex"] = -1;
123 vm["overriddenLayerName"] = QString();
124 vm["buildDataDefinedBlocks"] = DEFAULT_DXF_DATA_DEFINED_BLOCKS;
125 vm["dataDefinedBlocksMaximumNumberOfClasses"] = -1;
126
127 const QString title = layer->name();
128 addOption( vm, title, false );
129 }
130}
131
132void QgsProcessingDxfLayersPanelWidget::configureLayer()
133{
134 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
135 if ( selection.size() != 1 )
136 {
137 QMessageBox::warning( this, tr( "Configure Layer" ), tr( "Please select a single layer." ) );
138 return;
139 }
140
141 QStandardItem *item = mModel->itemFromIndex( selection[0] );
142 const QVariant value = item->data( Qt::UserRole );
143
145 if ( panel && panel->dockMode() )
146 {
147 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
148 widget->setPanelTitle( tr( "Configure Layer" ) );
149 widget->buttonBox()->hide();
150
151 connect( widget, &QgsProcessingDxfLayerDetailsWidget::widgetChanged, this, [this, item, widget]() { setItemValue( item, widget->value() ); } );
152 panel->openPanel( widget );
153 }
154 else
155 {
156 QDialog dlg;
157 dlg.setWindowTitle( tr( "Configure Layer" ) );
158 QVBoxLayout *vLayout = new QVBoxLayout();
159 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
160 vLayout->addWidget( widget );
161 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
162 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
163 dlg.setLayout( vLayout );
164 if ( dlg.exec() )
165 {
166 setItemValue( item, widget->value() );
167 }
168 }
169}
170
171void QgsProcessingDxfLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
172{
173 mContext.setProject( mProject );
174
175 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( value.toMap(), mContext );
176
177 item->setText( titleForLayer( layer ) );
178 item->setData( value, Qt::UserRole );
179}
180
181QString QgsProcessingDxfLayersPanelWidget::titleForLayer( const QgsDxfExport::DxfLayer &layer )
182{
183 QString title = layer.layer()->name();
184
185 // if both options are set, the split attribute takes precedence,
186 // so hide overridden message to give users a hint on the result.
187 if ( layer.layerOutputAttributeIndex() != -1 )
188 {
189 title += tr( " [split attribute: %1]" ).arg( layer.splitLayerAttribute() );
190 }
191 else
192 {
193 if ( !layer.overriddenName().isEmpty() )
194 {
195 title += tr( " [overridden name: %1]" ).arg( layer.overriddenName() );
196 }
197 }
198
199 return title;
200}
201
202
203//
204// QgsProcessingDxfLayersWidget
205//
206
207QgsProcessingDxfLayersWidget::QgsProcessingDxfLayersWidget( QWidget *parent )
208 : QWidget( parent )
209{
210 QHBoxLayout *hl = new QHBoxLayout();
211 hl->setContentsMargins( 0, 0, 0, 0 );
212
213 mLineEdit = new QLineEdit();
214 mLineEdit->setEnabled( false );
215 hl->addWidget( mLineEdit, 1 );
216
217 mToolButton = new QToolButton();
218 mToolButton->setText( QString( QChar( 0x2026 ) ) );
219 hl->addWidget( mToolButton );
220
221 setLayout( hl );
222
223 updateSummaryText();
224
225 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingDxfLayersWidget::showDialog );
226}
227
228void QgsProcessingDxfLayersWidget::setValue( const QVariant &value )
229{
230 if ( value.isValid() )
231 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
232 else
233 mValue.clear();
234
235 updateSummaryText();
236 emit changed();
237}
238
239void QgsProcessingDxfLayersWidget::setProject( QgsProject *project )
240{
241 mProject = project;
242}
243
244void QgsProcessingDxfLayersWidget::showDialog()
245{
247 if ( panel && panel->dockMode() )
248 {
249 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
250 widget->setPanelTitle( tr( "Input layers" ) );
251 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() { setValue( widget->selectedOptions() ); } );
252 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
253 panel->openPanel( widget );
254 }
255 else
256 {
257 QDialog dlg;
258 dlg.setWindowTitle( tr( "Input layers" ) );
259 QVBoxLayout *vLayout = new QVBoxLayout();
260 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
261 vLayout->addWidget( widget );
262 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
263 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
264 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
265 dlg.setLayout( vLayout );
266 if ( dlg.exec() )
267 {
268 setValue( widget->selectedOptions() );
269 }
270 }
271}
272
273void QgsProcessingDxfLayersWidget::updateSummaryText()
274{
275 mLineEdit->setText( tr( "%n vector layer(s) selected", nullptr, mValue.count() ) );
276}
277
278
279//
280// QgsProcessingDxfLayersWidgetWrapper
281//
282
283QgsProcessingDxfLayersWidgetWrapper::QgsProcessingDxfLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
284 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
285{}
286
287QString QgsProcessingDxfLayersWidgetWrapper::parameterType() const
288{
290}
291
292QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDxfLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
293{
294 return new QgsProcessingDxfLayersWidgetWrapper( parameter, type );
295}
296
297QWidget *QgsProcessingDxfLayersWidgetWrapper::createWidget()
298{
299 mPanel = new QgsProcessingDxfLayersWidget( nullptr );
300 mPanel->setProject( widgetContext().project() );
301 connect( mPanel, &QgsProcessingDxfLayersWidget::changed, this, [this] { emit widgetValueHasChanged( this ); } );
302 return mPanel;
303}
304
305void QgsProcessingDxfLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
306{
308 if ( mPanel )
309 {
310 mPanel->setProject( context.project() );
311 }
312}
313
314void QgsProcessingDxfLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
315{
316 Q_UNUSED( context )
317 if ( mPanel )
318 {
319 mPanel->setValue( value );
320 }
321}
322
323QVariant QgsProcessingDxfLayersWidgetWrapper::widgetValue() const
324{
325 return mPanel ? mPanel->value() : QVariant();
326}
327
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3647
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3786
@ Point
Points.
Definition qgis.h:380
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:87
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:113
Represents a vector layer which manages a vector based dataset.
Encapsulates the properties of a vector layer containing features that will be exported to the DXF fi...
QString overriddenName() const
Returns the overridden layer name to be used in the exported DXF.
bool buildDataDefinedBlocks() const
Returns true if data defined point block symbols should be created.
QgsVectorLayer * layer() const
Returns the source vector layer.
int dataDefinedBlocksMaximumNumberOfClasses() const
Returns the maximum number of data defined symbol classes for which blocks are created.
QString splitLayerAttribute() const
Returns the name of the field used to split the source layer's features into multiple exported DXF la...
int layerOutputAttributeIndex() const
Returns the attribute index used to split the source layer's features into multiple exported DXF laye...