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