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
16 #include "qgsprocessingdxflayerswidgetwrapper.h"
17
18 #include <QBoxLayout>
19 #include <QLineEdit>
20 #include <QMessageBox>
21 #include <QPushButton>
22 #include <QStandardItemModel>
23 #include <QToolButton>
24
25 #include "qgspanelwidget.h"
26 #include "qgsprocessingparameters.h"
27 #include "qgsprocessingoutputs.h"
28 #include "qgsprocessingparameterdxflayers.h"
29
30 /// @cond private
31
32 //
33 // QgsProcessingDxfLayerDetailsWidget
34 //
35
QgsProcessingDxfLayerDetailsWidget(const QVariant & value,QgsProject * project)36 QgsProcessingDxfLayerDetailsWidget::QgsProcessingDxfLayerDetailsWidget( const QVariant &value, QgsProject *project )
37 {
38 setupUi( this );
39
40 mFieldsComboBox->setAllowEmptyFieldName( true );
41
42 mContext.setProject( project );
43
44 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( value.toMap(), mContext );
45 mLayer = layer.layer();
46
47 if ( !mLayer )
48 return;
49
50 mFieldsComboBox->setLayer( mLayer );
51 mFieldsComboBox->setCurrentIndex( layer.layerOutputAttributeIndex() );
52
53 connect( mFieldsComboBox, &QgsFieldComboBox::fieldChanged, this, &QgsPanelWidget::widgetChanged );
54 }
55
value() const56 QVariant QgsProcessingDxfLayerDetailsWidget::value() const
57 {
58 const int index = mLayer->fields().lookupField( mFieldsComboBox->currentField() );
59 const QgsDxfExport::DxfLayer layer( mLayer, index );
60 return QgsProcessingParameterDxfLayers::layerAsVariantMap( layer );
61 }
62
63
64 //
65 // QgsProcessingDxfLayersPanelWidget
66 //
67
QgsProcessingDxfLayersPanelWidget(const QVariant & value,QgsProject * project,QWidget * parent)68 QgsProcessingDxfLayersPanelWidget::QgsProcessingDxfLayersPanelWidget(
69 const QVariant &value,
70 QgsProject *project,
71 QWidget *parent )
72 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
73 , mProject( project )
74 {
75 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
76
77 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Layer…" ) );
78 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingDxfLayersPanelWidget::configureLayer );
79 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
80
81 // populate the list: first layers already selected, then layers from project not yet selected
82 mContext.setProject( project );
83
84 QSet<const QgsVectorLayer *> seenVectorLayers;
85 const QVariantList valueList = value.toList();
86 for ( const QVariant &v : valueList )
87 {
88 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( v.toMap(), mContext );
89 if ( !layer.layer() )
90 continue; // skip any invalid layers
91
92 addOption( v, titleForLayer( layer ), true );
93 seenVectorLayers.insert( layer.layer() );
94 }
95
96 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList< int >() );
97 for ( const QgsVectorLayer *layer : options )
98 {
99 if ( seenVectorLayers.contains( layer ) )
100 continue;
101
102 QVariantMap vm;
103 vm["layer"] = layer->id();
104 vm["attributeIndex"] = -1;
105
106 const QString title = layer->name();
107 addOption( vm, title, false );
108 }
109 }
110
configureLayer()111 void QgsProcessingDxfLayersPanelWidget::configureLayer()
112 {
113 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
114 if ( selection.size() != 1 )
115 {
116 QMessageBox::warning( this, tr( "Configure Layer" ), tr( "Please select a single layer." ) );
117 return;
118 }
119
120 QStandardItem *item = mModel->itemFromIndex( selection[0] );
121 const QVariant value = item->data( Qt::UserRole );
122
123 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
124 if ( panel && panel->dockMode() )
125 {
126 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
127 widget->setPanelTitle( tr( "Configure Layer" ) );
128 widget->buttonBox()->hide();
129
130 connect( widget, &QgsProcessingDxfLayerDetailsWidget::widgetChanged, this, [ = ]()
131 {
132 setItemValue( item, widget->value() );
133 } );
134 panel->openPanel( widget );
135 }
136 else
137 {
138 QDialog dlg;
139 dlg.setWindowTitle( tr( "Configure Layer" ) );
140 QVBoxLayout *vLayout = new QVBoxLayout();
141 QgsProcessingDxfLayerDetailsWidget *widget = new QgsProcessingDxfLayerDetailsWidget( value, mProject );
142 vLayout->addWidget( widget );
143 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
144 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
145 dlg.setLayout( vLayout );
146 if ( dlg.exec() )
147 {
148 setItemValue( item, widget->value() );
149 }
150 }
151 }
152
setItemValue(QStandardItem * item,const QVariant & value)153 void QgsProcessingDxfLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
154 {
155 mContext.setProject( mProject );
156
157 const QgsDxfExport::DxfLayer layer = QgsProcessingParameterDxfLayers::variantMapAsLayer( value.toMap(), mContext );
158
159 item->setText( titleForLayer( layer ) );
160 item->setData( value, Qt::UserRole );
161 }
162
titleForLayer(const QgsDxfExport::DxfLayer & layer)163 QString QgsProcessingDxfLayersPanelWidget::titleForLayer( const QgsDxfExport::DxfLayer &layer )
164 {
165 QString title = layer.layer()->name();
166
167 if ( layer.layerOutputAttributeIndex() != -1 )
168 title += tr( " [split attribute: %1]" ).arg( layer.splitLayerAttribute() );
169
170 return title;
171 }
172
173
174 //
175 // QgsProcessingDxfLayersWidget
176 //
177
QgsProcessingDxfLayersWidget(QWidget * parent)178 QgsProcessingDxfLayersWidget::QgsProcessingDxfLayersWidget( QWidget *parent )
179 : QWidget( parent )
180 {
181 QHBoxLayout *hl = new QHBoxLayout();
182 hl->setContentsMargins( 0, 0, 0, 0 );
183
184 mLineEdit = new QLineEdit();
185 mLineEdit->setEnabled( false );
186 hl->addWidget( mLineEdit, 1 );
187
188 mToolButton = new QToolButton();
189 mToolButton->setText( QString( QChar( 0x2026 ) ) );
190 hl->addWidget( mToolButton );
191
192 setLayout( hl );
193
194 updateSummaryText();
195
196 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingDxfLayersWidget::showDialog );
197 }
198
setValue(const QVariant & value)199 void QgsProcessingDxfLayersWidget::setValue( const QVariant &value )
200 {
201 if ( value.isValid() )
202 mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
203 else
204 mValue.clear();
205
206 updateSummaryText();
207 emit changed();
208 }
209
setProject(QgsProject * project)210 void QgsProcessingDxfLayersWidget::setProject( QgsProject *project )
211 {
212 mProject = project;
213 }
214
showDialog()215 void QgsProcessingDxfLayersWidget::showDialog()
216 {
217 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
218 if ( panel && panel->dockMode() )
219 {
220 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
221 widget->setPanelTitle( tr( "Input layers" ) );
222 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
223 {
224 setValue( widget->selectedOptions() );
225 } );
226 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
227 panel->openPanel( widget );
228 }
229 else
230 {
231 QDialog dlg;
232 dlg.setWindowTitle( tr( "Input layers" ) );
233 QVBoxLayout *vLayout = new QVBoxLayout();
234 QgsProcessingDxfLayersPanelWidget *widget = new QgsProcessingDxfLayersPanelWidget( mValue, mProject );
235 vLayout->addWidget( widget );
236 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
237 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
238 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
239 dlg.setLayout( vLayout );
240 if ( dlg.exec() )
241 {
242 setValue( widget->selectedOptions() );
243 }
244 }
245 }
246
updateSummaryText()247 void QgsProcessingDxfLayersWidget::updateSummaryText()
248 {
249 mLineEdit->setText( tr( "%1 vector layers selected" ).arg( mValue.count() ) );
250 }
251
252
253 //
254 // QgsProcessingDxfLayersWidgetWrapper
255 //
256
QgsProcessingDxfLayersWidgetWrapper(const QgsProcessingParameterDefinition * parameter,QgsProcessingGui::WidgetType type,QWidget * parent)257 QgsProcessingDxfLayersWidgetWrapper::QgsProcessingDxfLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
258 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
259 {
260 }
261
parameterType() const262 QString QgsProcessingDxfLayersWidgetWrapper::parameterType() const
263 {
264 return QgsProcessingParameterDxfLayers::typeName();
265 }
266
createWidgetWrapper(const QgsProcessingParameterDefinition * parameter,QgsProcessingGui::WidgetType type)267 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDxfLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
268 {
269 return new QgsProcessingDxfLayersWidgetWrapper( parameter, type );
270 }
271
createWidget()272 QWidget *QgsProcessingDxfLayersWidgetWrapper::createWidget()
273 {
274 mPanel = new QgsProcessingDxfLayersWidget( nullptr );
275 mPanel->setProject( widgetContext().project() );
276 connect( mPanel, &QgsProcessingDxfLayersWidget::changed, this, [ = ]
277 {
278 emit widgetValueHasChanged( this );
279 } );
280 return mPanel;
281 }
282
setWidgetContext(const QgsProcessingParameterWidgetContext & context)283 void QgsProcessingDxfLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
284 {
285 QgsAbstractProcessingParameterWidgetWrapper::setWidgetContext( context );
286 if ( mPanel )
287 {
288 mPanel->setProject( context.project() );
289 }
290 }
291
setWidgetValue(const QVariant & value,QgsProcessingContext & context)292 void QgsProcessingDxfLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
293 {
294 Q_UNUSED( context )
295 if ( mPanel )
296 {
297 mPanel->setValue( value );
298 }
299 }
300
widgetValue() const301 QVariant QgsProcessingDxfLayersWidgetWrapper::widgetValue() const
302 {
303 return mPanel ? mPanel->value() : QVariant();
304 }
305
compatibleParameterTypes() const306 QStringList QgsProcessingDxfLayersWidgetWrapper::compatibleParameterTypes() const
307 {
308 return QStringList()
309 << QgsProcessingParameterMultipleLayers::typeName()
310 << QgsProcessingParameterMapLayer::typeName()
311 << QgsProcessingParameterVectorLayer::typeName()
312 << QgsProcessingParameterFeatureSource::typeName()
313 << QgsProcessingParameterFile::typeName()
314 << QgsProcessingParameterString::typeName();
315 }
316
compatibleOutputTypes() const317 QStringList QgsProcessingDxfLayersWidgetWrapper::compatibleOutputTypes() const
318 {
319 return QStringList()
320 << QgsProcessingOutputString::typeName()
321 << QgsProcessingOutputMapLayer::typeName()
322 << QgsProcessingOutputVectorLayer::typeName()
323 << QgsProcessingOutputMultipleLayers::typeName()
324 << QgsProcessingOutputFile::typeName();
325 }
326
327 /// @endcond
328