1 /***************************************************************************
2 qgsprocessingvectortilewriterlayerswidgetwrapper.cpp
3 ---------------------
4 Date : April 2020
5 Copyright : (C) 2020 by Martin Dobias
6 Email : wonder dot sk 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 "qgsprocessingvectortilewriterlayerswidgetwrapper.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
27 #include "qgsvectortilewriter.h"
28
29 #include "qgsprocessingparametervectortilewriterlayers.h"
30
31 /// @cond private
32
33 //
34 // QgsProcessingVectorTileWriteLayerDetailsWidget
35 //
36
QgsProcessingVectorTileWriteLayerDetailsWidget(const QVariant & value,QgsProject * project)37 QgsProcessingVectorTileWriteLayerDetailsWidget::QgsProcessingVectorTileWriteLayerDetailsWidget( const QVariant &value, QgsProject *project )
38 {
39 setupUi( this );
40
41 mContext.setProject( project );
42
43 const QgsVectorTileWriter::Layer layer = QgsProcessingParameterVectorTileWriterLayers::variantMapAsLayer( value.toMap(), mContext );
44 mLayer = layer.layer();
45
46 if ( !mLayer )
47 return;
48
49 mSpinMinZoom->setClearValue( -1, tr( "Not set" ) );
50 mSpinMaxZoom->setClearValue( -1, tr( "Not set" ) );
51 mEditFilterExpression->setMultiLine( true );
52 mEditFilterExpression->setLayer( mLayer );
53
54 mSpinMinZoom->setValue( layer.minZoom() );
55 mSpinMaxZoom->setValue( layer.maxZoom() );
56 mEditLayerName->setText( layer.layerName() );
57 mEditLayerName->setPlaceholderText( mLayer->name() );
58 mEditFilterExpression->setExpression( layer.filterExpression() );
59
60 connect( mSpinMinZoom, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
61 connect( mSpinMaxZoom, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
62 connect( mEditLayerName, &QLineEdit::textChanged, this, &QgsPanelWidget::widgetChanged );
63 connect( mEditFilterExpression, &QgsExpressionLineEdit::expressionChanged, this, &QgsPanelWidget::widgetChanged );
64 }
65
value() const66 QVariant QgsProcessingVectorTileWriteLayerDetailsWidget::value() const
67 {
68 QgsVectorTileWriter::Layer layer( mLayer );
69 layer.setMinZoom( mSpinMinZoom->value() );
70 layer.setMaxZoom( mSpinMaxZoom->value() );
71 layer.setLayerName( mEditLayerName->text() );
72 layer.setFilterExpression( mEditFilterExpression->expression() );
73 return QgsProcessingParameterVectorTileWriterLayers::layerAsVariantMap( layer );
74 }
75
76 //
77 // QgsProcessingVectorTileWriterLayersPanelWidget
78 //
79
80
QgsProcessingVectorTileWriterLayersPanelWidget(const QVariant & value,QgsProject * project,QWidget * parent)81 QgsProcessingVectorTileWriterLayersPanelWidget::QgsProcessingVectorTileWriterLayersPanelWidget(
82 const QVariant &value,
83 QgsProject *project,
84 QWidget *parent )
85 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
86 , mProject( project )
87 {
88
89 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingVectorTileWriterLayersPanelWidget::configureLayer );
90
91 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Layer…" ) );
92 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingVectorTileWriterLayersPanelWidget::configureLayer );
93 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
94
95 QPushButton *copyLayerButton = new QPushButton( tr( "Copy Layer" ) );
96 connect( copyLayerButton, &QPushButton::clicked, this, &QgsProcessingVectorTileWriterLayersPanelWidget::copyLayer );
97 buttonBox()->addButton( copyLayerButton, 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 {
106 const QgsVectorTileWriter::Layer layer = QgsProcessingParameterVectorTileWriterLayers::variantMapAsLayer( v.toMap(), mContext );
107 if ( !layer.layer() )
108 continue; // skip any invalid layers
109
110 addOption( v, titleForLayer( layer ), true );
111
112 seenVectorLayers.insert( layer.layer() );
113 }
114
115 const QList<QgsVectorLayer *> options = QgsProcessingUtils::compatibleVectorLayers( project, QList< int >() );
116 for ( const QgsVectorLayer *layer : options )
117 {
118 if ( seenVectorLayers.contains( layer ) )
119 continue;
120
121 QVariantMap vm;
122 vm["layer"] = layer->id();
123
124 const QString title = layer->name();
125
126 addOption( vm, title, false );
127 }
128 }
129
configureLayer()130 void QgsProcessingVectorTileWriterLayersPanelWidget::configureLayer()
131 {
132 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
133 if ( selection.size() != 1 )
134 {
135 QMessageBox::warning( this, tr( "Configure Layer" ), tr( "Please select a single layer." ) );
136 return;
137 }
138
139 QStandardItem *item = mModel->itemFromIndex( selection[0] );
140 const QVariant value = item->data( Qt::UserRole );
141
142 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
143 if ( panel && panel->dockMode() )
144 {
145 QgsProcessingVectorTileWriteLayerDetailsWidget *widget = new QgsProcessingVectorTileWriteLayerDetailsWidget( value, mProject );
146 widget->setPanelTitle( tr( "Configure Layer" ) );
147 widget->buttonBox()->hide();
148
149 connect( widget, &QgsProcessingVectorTileWriteLayerDetailsWidget::widgetChanged, this, [ = ]()
150 {
151 setItemValue( item, widget->value() );
152 } );
153 panel->openPanel( widget );
154 }
155 else
156 {
157 QDialog dlg;
158 dlg.setWindowTitle( tr( "Configure Layer" ) );
159 QVBoxLayout *vLayout = new QVBoxLayout();
160 QgsProcessingVectorTileWriteLayerDetailsWidget *widget = new QgsProcessingVectorTileWriteLayerDetailsWidget( value, mProject );
161 vLayout->addWidget( widget );
162 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
163 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
164 dlg.setLayout( vLayout );
165 if ( dlg.exec() )
166 {
167 setItemValue( item, widget->value() );
168 }
169 }
170 }
171
copyLayer()172 void QgsProcessingVectorTileWriterLayersPanelWidget::copyLayer()
173 {
174 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
175 if ( selection.size() != 1 )
176 {
177 QMessageBox::warning( this, tr( "Copy Layer" ), tr( "Please select a single layer." ) );
178 return;
179 }
180
181 QStandardItem *item = mModel->itemFromIndex( selection[0] );
182 const QVariant value = item->data( Qt::UserRole );
183 mModel->insertRow( selection[0].row() + 1, item->clone() );
184 }
185
setItemValue(QStandardItem * item,const QVariant & value)186 void QgsProcessingVectorTileWriterLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
187 {
188 mContext.setProject( mProject );
189
190 const QgsVectorTileWriter::Layer layer = QgsProcessingParameterVectorTileWriterLayers::variantMapAsLayer( value.toMap(), mContext );
191
192 item->setText( titleForLayer( layer ) );
193 item->setData( value, Qt::UserRole );
194 }
195
titleForLayer(const QgsVectorTileWriter::Layer & layer)196 QString QgsProcessingVectorTileWriterLayersPanelWidget::titleForLayer( const QgsVectorTileWriter::Layer &layer )
197 {
198 QString title = layer.layer()->name();
199
200 // add more details
201 if ( layer.minZoom() >= 0 && layer.maxZoom() >= 0 )
202 title += tr( " [zoom %1...%2]" ).arg( layer.minZoom() ).arg( layer.maxZoom() );
203 else if ( layer.minZoom() >= 0 )
204 title += tr( " [zoom >= %1]" ).arg( layer.minZoom() );
205 else if ( layer.maxZoom() >= 0 )
206 title += tr( " [zoom <= %1]" ).arg( layer.maxZoom() );
207
208 if ( !layer.layerName().isEmpty() )
209 title += tr( " [name: %1]" ).arg( layer.layerName() );
210 if ( !layer.filterExpression().isEmpty() )
211 title += tr( " [with filter]" );
212
213 return title;
214 }
215
216
217 //
218 // QgsProcessingVectorTileWriterLayersWidget
219 //
220
221
QgsProcessingVectorTileWriterLayersWidget(QWidget * parent)222 QgsProcessingVectorTileWriterLayersWidget::QgsProcessingVectorTileWriterLayersWidget( QWidget *parent )
223 : QWidget( parent )
224 {
225 QHBoxLayout *hl = new QHBoxLayout();
226 hl->setContentsMargins( 0, 0, 0, 0 );
227
228 mLineEdit = new QLineEdit();
229 mLineEdit->setEnabled( false );
230 hl->addWidget( mLineEdit, 1 );
231
232 mToolButton = new QToolButton();
233 mToolButton->setText( QString( QChar( 0x2026 ) ) );
234 hl->addWidget( mToolButton );
235
236 setLayout( hl );
237
238 updateSummaryText();
239
240 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingVectorTileWriterLayersWidget::showDialog );
241 }
242
setValue(const QVariant & value)243 void QgsProcessingVectorTileWriterLayersWidget::setValue( const QVariant &value )
244 {
245 if ( value.isValid() )
246 mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
247 else
248 mValue.clear();
249
250 updateSummaryText();
251 emit changed();
252 }
253
setProject(QgsProject * project)254 void QgsProcessingVectorTileWriterLayersWidget::setProject( QgsProject *project )
255 {
256 mProject = project;
257 }
258
showDialog()259 void QgsProcessingVectorTileWriterLayersWidget::showDialog()
260 {
261 QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
262 if ( panel && panel->dockMode() )
263 {
264 QgsProcessingVectorTileWriterLayersPanelWidget *widget = new QgsProcessingVectorTileWriterLayersPanelWidget( mValue, mProject );
265 widget->setPanelTitle( tr( "Input layers" ) );
266 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
267 {
268 setValue( widget->selectedOptions() );
269 } );
270 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
271 panel->openPanel( widget );
272 }
273 else
274 {
275 QDialog dlg;
276 dlg.setWindowTitle( tr( "Input layers" ) );
277 QVBoxLayout *vLayout = new QVBoxLayout();
278 QgsProcessingVectorTileWriterLayersPanelWidget *widget = new QgsProcessingVectorTileWriterLayersPanelWidget( mValue, mProject );
279 vLayout->addWidget( widget );
280 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
281 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
282 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
283 dlg.setLayout( vLayout );
284 if ( dlg.exec() )
285 {
286 setValue( widget->selectedOptions() );
287 }
288 }
289 }
290
updateSummaryText()291 void QgsProcessingVectorTileWriterLayersWidget::updateSummaryText()
292 {
293 mLineEdit->setText( tr( "%1 vector layers selected" ).arg( mValue.count() ) );
294 }
295
296 //
297 // QgsProcessingVectorTileWriterLayersWidgetWrapper
298 //
299
QgsProcessingVectorTileWriterLayersWidgetWrapper(const QgsProcessingParameterDefinition * parameter,QgsProcessingGui::WidgetType type,QWidget * parent)300 QgsProcessingVectorTileWriterLayersWidgetWrapper::QgsProcessingVectorTileWriterLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
301 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
302 {
303 }
304
parameterType() const305 QString QgsProcessingVectorTileWriterLayersWidgetWrapper::parameterType() const
306 {
307 return QgsProcessingParameterVectorTileWriterLayers::typeName();
308 }
309
createWidgetWrapper(const QgsProcessingParameterDefinition * parameter,QgsProcessingGui::WidgetType type)310 QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorTileWriterLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
311 {
312 return new QgsProcessingVectorTileWriterLayersWidgetWrapper( parameter, type );
313 }
314
createWidget()315 QWidget *QgsProcessingVectorTileWriterLayersWidgetWrapper::createWidget()
316 {
317 mPanel = new QgsProcessingVectorTileWriterLayersWidget( nullptr );
318 mPanel->setProject( widgetContext().project() );
319 connect( mPanel, &QgsProcessingVectorTileWriterLayersWidget::changed, this, [ = ]
320 {
321 emit widgetValueHasChanged( this );
322 } );
323 return mPanel;
324 }
325
setWidgetContext(const QgsProcessingParameterWidgetContext & context)326 void QgsProcessingVectorTileWriterLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
327 {
328 QgsAbstractProcessingParameterWidgetWrapper::setWidgetContext( context );
329 if ( mPanel )
330 {
331 mPanel->setProject( context.project() );
332 }
333 }
334
setWidgetValue(const QVariant & value,QgsProcessingContext & context)335 void QgsProcessingVectorTileWriterLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
336 {
337 Q_UNUSED( context )
338 if ( mPanel )
339 {
340 mPanel->setValue( value );
341 }
342 }
343
widgetValue() const344 QVariant QgsProcessingVectorTileWriterLayersWidgetWrapper::widgetValue() const
345 {
346 return mPanel ? mPanel->value() : QVariant();
347 }
348
compatibleParameterTypes() const349 QStringList QgsProcessingVectorTileWriterLayersWidgetWrapper::compatibleParameterTypes() const
350 {
351 return QStringList();
352 }
353
compatibleOutputTypes() const354 QStringList QgsProcessingVectorTileWriterLayersWidgetWrapper::compatibleOutputTypes() const
355 {
356 return QStringList();
357 }
358
359 /// @endcond
360