1 /***************************************************************************
2     qgsvectorlayerdigitizingproperties.cpp
3     --------------------------------------
4   copyright            : (C) 2018 by Matthias Kuhn
5   email                : matthias@opengis.ch
6  ***************************************************************************/
7 
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 #include "qgsvectorlayerdigitizingproperties.h"
18 #include "qgsanalysis.h"
19 #include "qgscollapsiblegroupbox.h"
20 #include "qgsdoublespinbox.h"
21 #include "qgsgeometrycheckfactory.h"
22 #include "qgsgeometrycheckregistry.h"
23 #include "qgsgeometrycheck.h"
24 #include "qgsgeometryoptions.h"
25 #include "qgsmaplayercombobox.h"
26 #include "qgsproject.h"
27 
28 #include <QFormLayout>
29 
QgsVectorLayerDigitizingPropertiesPage(QgsMapLayer * layer,QgsMapCanvas * canvas,QWidget * parent)30 QgsVectorLayerDigitizingPropertiesPage::QgsVectorLayerDigitizingPropertiesPage( QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent )
31   : QgsMapLayerConfigWidget( layer, canvas, parent )
32 {
33   setupUi( this );
34 
35   QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayer );
36 
37   if ( vlayer && vlayer->isSpatial() )
38   {
39     mRemoveDuplicateNodesCheckbox->setEnabled( true );
40     mGeometryPrecisionLineEdit->setEnabled( true );
41     mGeometryPrecisionLineEdit->setValidator( new QDoubleValidator( mGeometryPrecisionLineEdit ) );
42 
43     const double precision( vlayer->geometryOptions()->geometryPrecision() );
44     const bool ok = true;
45     QString precisionStr( QLocale().toString( precision, ok ) );
46     if ( precision == 0.0 || ! ok )
47       precisionStr = QString();
48     mGeometryPrecisionLineEdit->setText( precisionStr );
49 
50     mRemoveDuplicateNodesManuallyActivated = vlayer->geometryOptions()->removeDuplicateNodes();
51     mRemoveDuplicateNodesCheckbox->setChecked( mRemoveDuplicateNodesManuallyActivated );
52     if ( !precisionStr.isNull() )
53       mRemoveDuplicateNodesCheckbox->setEnabled( false );
54     connect( mGeometryPrecisionLineEdit, &QLineEdit::textChanged, this, [this]
55     {
56       if ( !mGeometryPrecisionLineEdit->text().isEmpty() )
57       {
58         if ( mRemoveDuplicateNodesCheckbox->isEnabled() )
59           mRemoveDuplicateNodesManuallyActivated  = mRemoveDuplicateNodesCheckbox->isChecked();
60         mRemoveDuplicateNodesCheckbox->setEnabled( false );
61         mRemoveDuplicateNodesCheckbox->setChecked( true );
62       }
63       else
64       {
65         mRemoveDuplicateNodesCheckbox->setEnabled( true );
66         mRemoveDuplicateNodesCheckbox->setChecked( mRemoveDuplicateNodesManuallyActivated );
67       }
68     } );
69 
70     mPrecisionUnitsLabel->setText( QStringLiteral( "[%1]" ).arg( QgsUnitTypes::toAbbreviatedString( vlayer->crs().mapUnits() ) ) );
71 
72     QLayout *geometryCheckLayout = new QVBoxLayout();
73     const QList<QgsGeometryCheckFactory *> geometryCheckFactories = QgsAnalysis::instance()->geometryCheckRegistry()->geometryCheckFactories( vlayer, QgsGeometryCheck::FeatureNodeCheck, QgsGeometryCheck::Flag::AvailableInValidation );
74     const QStringList activeChecks = vlayer->geometryOptions()->geometryChecks();
75     for ( const QgsGeometryCheckFactory *factory : geometryCheckFactories )
76     {
77       QCheckBox *cb = new QCheckBox( factory->description() );
78       cb->setChecked( activeChecks.contains( factory->id() ) );
79       mGeometryCheckFactoriesGroupBoxes.insert( cb, factory->id() );
80       geometryCheckLayout->addWidget( cb );
81     }
82     mGeometryValidationGroupBox->setLayout( geometryCheckLayout );
83     mGeometryValidationGroupBox->setVisible( !geometryCheckFactories.isEmpty() );
84 
85     QLayout *topologyCheckLayout = new QVBoxLayout();
86     const QList<QgsGeometryCheckFactory *> topologyCheckFactories = QgsAnalysis::instance()->geometryCheckRegistry()->geometryCheckFactories( vlayer, QgsGeometryCheck::LayerCheck, QgsGeometryCheck::Flag::AvailableInValidation );
87 
88     for ( const QgsGeometryCheckFactory *factory : topologyCheckFactories )
89     {
90       QCheckBox *cb = new QCheckBox( factory->description() );
91       cb->setChecked( activeChecks.contains( factory->id() ) );
92       mGeometryCheckFactoriesGroupBoxes.insert( cb, factory->id() );
93       topologyCheckLayout->addWidget( cb );
94       if ( factory->id() == QLatin1String( "QgsGeometryGapCheck" ) )
95       {
96         const QVariantMap gapCheckConfig = vlayer->geometryOptions()->checkConfiguration( QStringLiteral( "QgsGeometryGapCheck" ) );
97 
98         mGapCheckAllowExceptionsActivatedCheckBox = new QgsCollapsibleGroupBox( tr( "Allowed Gaps" ) );
99         mGapCheckAllowExceptionsActivatedCheckBox->setCheckable( true );
100         mGapCheckAllowExceptionsActivatedCheckBox->setChecked( gapCheckConfig.value( QStringLiteral( "allowedGapsEnabled" ), false ).toBool() );
101         QGridLayout *layout = new QGridLayout();
102         mGapCheckAllowExceptionsActivatedCheckBox->setLayout( layout );
103         topologyCheckLayout->addWidget( mGapCheckAllowExceptionsActivatedCheckBox );
104         mGapCheckAllowExceptionsLayerComboBox = new QgsMapLayerComboBox();
105         mGapCheckAllowExceptionsLayerComboBox->setFilters( QgsMapLayerProxyModel::PolygonLayer );
106         mGapCheckAllowExceptionsLayerComboBox->setExceptedLayerList( QList<QgsMapLayer *> { vlayer } );
107         mGapCheckAllowExceptionsLayerComboBox->setLayer( QgsProject::instance()->mapLayer( gapCheckConfig.value( QStringLiteral( "allowedGapsLayer" ) ).toString() ) );
108         layout->addWidget( new QLabel( tr( "Layer" ) ), 0, 0 );
109         layout->addWidget( mGapCheckAllowExceptionsLayerComboBox, 0, 1 );
110         mGapCheckAllowExceptionsBufferSpinBox = new QgsDoubleSpinBox();
111         mGapCheckAllowExceptionsBufferSpinBox->setInputMethodHints( Qt::ImhFormattedNumbersOnly );
112         mGapCheckAllowExceptionsBufferSpinBox->setSuffix( QgsUnitTypes::toAbbreviatedString( vlayer->crs().mapUnits() ) );
113         mGapCheckAllowExceptionsBufferSpinBox->setValue( gapCheckConfig.value( QStringLiteral( "allowedGapsBuffer" ) ).toDouble() );
114         layout->addWidget( new QLabel( tr( "Buffer" ) ), 0, 2 );
115         layout->addWidget( mGapCheckAllowExceptionsBufferSpinBox, 0, 3 );
116       }
117     }
118     mTopologyChecksGroupBox->setLayout( topologyCheckLayout );
119     mTopologyChecksGroupBox->setVisible( !topologyCheckFactories.isEmpty() );
120   }
121   else
122   {
123     mRemoveDuplicateNodesCheckbox->setEnabled( false );
124     mGeometryPrecisionLineEdit->setEnabled( false );
125     mGeometryAutoFixesGroupBox->setEnabled( false );
126   }
127 
128   setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#digitizing-properties" ) );
129 }
130 
apply()131 void QgsVectorLayerDigitizingPropertiesPage::apply()
132 {
133   QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayer );
134   if ( !vlayer )
135   {
136     return;
137   }
138 
139   vlayer->geometryOptions()->setRemoveDuplicateNodes( mRemoveDuplicateNodesCheckbox->isChecked() );
140   bool ok = true;
141   double precision( QLocale().toDouble( mGeometryPrecisionLineEdit->text(), &ok ) );
142   if ( ! ok )
143     precision = 0.0;
144   vlayer->geometryOptions()->setGeometryPrecision( precision );
145 
146   QStringList activeChecks;
147   QHash<QCheckBox *, QString>::const_iterator it;
148   for ( it = mGeometryCheckFactoriesGroupBoxes.constBegin(); it != mGeometryCheckFactoriesGroupBoxes.constEnd(); ++it )
149   {
150     if ( it.key()->isChecked() )
151       activeChecks << it.value();
152   }
153   vlayer->geometryOptions()->setGeometryChecks( activeChecks );
154 
155   if ( mGapCheckAllowExceptionsActivatedCheckBox )
156   {
157     QVariantMap gapCheckConfig;
158     gapCheckConfig.insert( QStringLiteral( "allowedGapsEnabled" ), mGapCheckAllowExceptionsActivatedCheckBox->isChecked() );
159     QgsMapLayer *currentLayer = mGapCheckAllowExceptionsLayerComboBox->currentLayer();
160     gapCheckConfig.insert( QStringLiteral( "allowedGapsLayer" ), currentLayer ? currentLayer->id() : QString() );
161     gapCheckConfig.insert( QStringLiteral( "allowedGapsBuffer" ), mGapCheckAllowExceptionsBufferSpinBox->value() );
162 
163     vlayer->geometryOptions()->setCheckConfiguration( QStringLiteral( "QgsGeometryGapCheck" ), gapCheckConfig );
164   }
165 }
166 
167 
QgsVectorLayerDigitizingPropertiesFactory(QObject * parent)168 QgsVectorLayerDigitizingPropertiesFactory::QgsVectorLayerDigitizingPropertiesFactory( QObject *parent )
169   : QObject( parent )
170 {
171   setIcon( QIcon( ":/images/themes/default/propertyicons/digitizing.svg" ) );
172   setTitle( tr( "Digitizing" ) );
173 }
174 
createWidget(QgsMapLayer * layer,QgsMapCanvas * canvas,bool dockWidget,QWidget * parent) const175 QgsMapLayerConfigWidget *QgsVectorLayerDigitizingPropertiesFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget, QWidget *parent ) const
176 {
177   Q_UNUSED( dockWidget )
178   return new QgsVectorLayerDigitizingPropertiesPage( layer, canvas, parent );
179 }
180 
supportsLayer(QgsMapLayer * layer) const181 bool QgsVectorLayerDigitizingPropertiesFactory::supportsLayer( QgsMapLayer *layer ) const
182 {
183   return layer->type() == QgsMapLayerType::VectorLayer;
184 }
185