Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsprojectsnappingsettings.cpp - QgsProjectSnappingSettings
3 : :
4 : : ---------------------
5 : : begin : 29.8.2016
6 : : copyright : (C) 2016 by Denis Rouzaud
7 : : email : denis.rouzaud@gmail.com
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 : : #include "qgssnappingconfig.h"
17 : :
18 : : #include <QDomElement>
19 : : #include <QHeaderView>
20 : : #include <QRegularExpression>
21 : :
22 : : #include "qgssettings.h"
23 : : #include "qgslogger.h"
24 : : #include "qgsvectorlayer.h"
25 : : #include "qgsproject.h"
26 : : #include "qgsapplication.h"
27 : :
28 : :
29 : 1 : QgsSnappingConfig::IndividualLayerSettings::IndividualLayerSettings( bool enabled, SnappingTypeFlag type, double tolerance, QgsTolerance::UnitType units, double minScale, double maxScale )
30 : 1 : : mValid( true )
31 : 1 : , mEnabled( enabled )
32 : 1 : , mType( type )
33 : 1 : , mTolerance( tolerance )
34 : 1 : , mUnits( units )
35 : 1 : , mMinimumScale( minScale )
36 : 1 : , mMaximumScale( maxScale )
37 : 1 : {}
38 : :
39 : 0 : QgsSnappingConfig::IndividualLayerSettings::IndividualLayerSettings( bool enabled, SnappingType type, double tolerance, QgsTolerance::UnitType units )
40 : 0 : : mValid( true )
41 : 0 : , mEnabled( enabled )
42 : 0 : , mTolerance( tolerance )
43 : 0 : , mUnits( units )
44 : : {
45 : : Q_NOWARN_DEPRECATED_PUSH
46 : 0 : setType( type );
47 : : Q_NOWARN_DEPRECATED_POP
48 : 0 : }
49 : :
50 : 0 : bool QgsSnappingConfig::IndividualLayerSettings::valid() const
51 : : {
52 : 0 : return mValid;
53 : : }
54 : :
55 : 0 : bool QgsSnappingConfig::IndividualLayerSettings::enabled() const
56 : : {
57 : 0 : return mEnabled;
58 : : }
59 : :
60 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setEnabled( bool enabled )
61 : : {
62 : 0 : mEnabled = enabled;
63 : 0 : }
64 : :
65 : 0 : QgsSnappingConfig::SnappingTypeFlag QgsSnappingConfig::IndividualLayerSettings::typeFlag() const
66 : : {
67 : 0 : return mType;
68 : : }
69 : :
70 : 0 : QgsSnappingConfig::SnappingType QgsSnappingConfig::IndividualLayerSettings::type() const
71 : : {
72 : :
73 : 0 : if ( ( mType & SegmentFlag ) && ( mType & VertexFlag ) )
74 : 0 : return QgsSnappingConfig::SnappingType::VertexAndSegment;
75 : 0 : else if ( mType & SegmentFlag )
76 : 0 : return QgsSnappingConfig::SnappingType::Segment;
77 : : else
78 : 0 : return QgsSnappingConfig::SnappingType::Vertex;
79 : :
80 : 0 : }
81 : :
82 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setType( QgsSnappingConfig::SnappingType type )
83 : : {
84 : 0 : switch ( type )
85 : : {
86 : : case 1:
87 : 0 : mType = VertexFlag;
88 : 0 : break;
89 : : case 2:
90 : 0 : mType = VertexFlag | SegmentFlag;
91 : 0 : break;
92 : : case 3:
93 : 0 : mType = SegmentFlag;
94 : 0 : break;
95 : : default:
96 : 0 : mType = NoSnapFlag;
97 : 0 : break;
98 : : }
99 : 0 : }
100 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setTypeFlag( QgsSnappingConfig::SnappingTypeFlag type )
101 : : {
102 : 0 : mType = type;
103 : 0 : }
104 : :
105 : 0 : double QgsSnappingConfig::IndividualLayerSettings::tolerance() const
106 : : {
107 : 0 : return mTolerance;
108 : : }
109 : :
110 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setTolerance( double tolerance )
111 : : {
112 : 0 : mTolerance = tolerance;
113 : 0 : }
114 : :
115 : 0 : QgsTolerance::UnitType QgsSnappingConfig::IndividualLayerSettings::units() const
116 : : {
117 : 0 : return mUnits;
118 : : }
119 : :
120 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setUnits( QgsTolerance::UnitType units )
121 : : {
122 : 0 : mUnits = units;
123 : 0 : }
124 : :
125 : 0 : double QgsSnappingConfig::IndividualLayerSettings::minimumScale() const
126 : : {
127 : 0 : return mMinimumScale;
128 : : }
129 : :
130 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setMinimumScale( double minScale )
131 : : {
132 : 0 : mMinimumScale = minScale;
133 : 0 : }
134 : :
135 : 0 : double QgsSnappingConfig::IndividualLayerSettings::maximumScale() const
136 : : {
137 : 0 : return mMaximumScale;
138 : : }
139 : :
140 : 0 : void QgsSnappingConfig::IndividualLayerSettings::setMaximumScale( double maxScale )
141 : : {
142 : 0 : mMaximumScale = maxScale;
143 : 0 : }
144 : :
145 : 0 : bool QgsSnappingConfig::IndividualLayerSettings::operator !=( const QgsSnappingConfig::IndividualLayerSettings &other ) const
146 : : {
147 : 0 : return mValid != other.mValid
148 : 0 : || mEnabled != other.mEnabled
149 : 0 : || mType != other.mType
150 : 0 : || mTolerance != other.mTolerance
151 : 0 : || mUnits != other.mUnits
152 : 0 : || mMinimumScale != other.mMinimumScale
153 : 0 : || mMaximumScale != other.mMaximumScale;
154 : : }
155 : :
156 : 0 : bool QgsSnappingConfig::IndividualLayerSettings::operator ==( const QgsSnappingConfig::IndividualLayerSettings &other ) const
157 : : {
158 : 0 : return mValid == other.mValid
159 : 0 : && mEnabled == other.mEnabled
160 : 0 : && mType == other.mType
161 : 0 : && mTolerance == other.mTolerance
162 : 0 : && mUnits == other.mUnits
163 : 0 : && mMinimumScale == other.mMinimumScale
164 : 0 : && mMaximumScale == other.mMaximumScale;
165 : : }
166 : :
167 : 5 : QgsSnappingConfig::QgsSnappingConfig( QgsProject *project )
168 : 5 : : mProject( project )
169 : : {
170 : 5 : if ( project )
171 : 5 : reset();
172 : 5 : }
173 : :
174 : 0 : bool QgsSnappingConfig::operator==( const QgsSnappingConfig &other ) const
175 : : {
176 : 0 : return mEnabled == other.mEnabled
177 : 0 : && mMode == other.mMode
178 : 0 : && mType == other.mType
179 : 0 : && mTolerance == other.mTolerance
180 : 0 : && mUnits == other.mUnits
181 : 0 : && mIntersectionSnapping == other.mIntersectionSnapping
182 : 0 : && mSelfSnapping == other.mSelfSnapping
183 : 0 : && mIndividualLayerSettings == other.mIndividualLayerSettings
184 : 0 : && mScaleDependencyMode == other.mScaleDependencyMode
185 : 0 : && mMinimumScale == other.mMinimumScale
186 : 0 : && mMaximumScale == other.mMaximumScale;
187 : : }
188 : :
189 : 13 : void QgsSnappingConfig::reset()
190 : : {
191 : : // get defaults values. They are both used for standard and advanced configuration (per layer)
192 : 26 : bool enabled = QgsSettings().value( QStringLiteral( "/qgis/digitizing/default_snap_enabled" ), false ).toBool();
193 : 26 : SnappingMode mode = QgsSettings().enumValue( QStringLiteral( "/qgis/digitizing/default_snap_mode" ), AllLayers );
194 : 13 : if ( mode == 0 )
195 : : {
196 : : // backward compatibility with QGIS 2.x
197 : : // could be removed in 3.4+
198 : 0 : mode = AllLayers;
199 : 0 : }
200 : 26 : QgsSnappingConfig::SnappingTypeFlag type = QgsSettings().flagValue( QStringLiteral( "/qgis/digitizing/default_snap_type" ), VertexFlag );
201 : 26 : double tolerance = QgsSettings().value( QStringLiteral( "/qgis/digitizing/default_snapping_tolerance" ), Qgis::DEFAULT_SNAP_TOLERANCE ).toDouble();
202 : 26 : QgsTolerance::UnitType units = QgsSettings().enumValue( QStringLiteral( "/qgis/digitizing/default_snapping_tolerance_unit" ), Qgis::DEFAULT_SNAP_UNITS );
203 : :
204 : : // assign main (standard) config
205 : 13 : mEnabled = enabled;
206 : 13 : mMode = mode;
207 : 13 : mType = type;
208 : 13 : mTolerance = tolerance;
209 : 13 : mScaleDependencyMode = Disabled;
210 : 13 : mMinimumScale = 0.0;
211 : 13 : mMaximumScale = 0.0;
212 : : // do not allow unit to be "layer" if not in advanced configuration
213 : 13 : if ( mUnits == QgsTolerance::LayerUnits && mMode != AdvancedConfiguration )
214 : : {
215 : 0 : mUnits = QgsTolerance::ProjectUnits;
216 : 0 : }
217 : : else
218 : : {
219 : 13 : mUnits = units;
220 : : }
221 : 13 : mIntersectionSnapping = false;
222 : 13 : mSelfSnapping = false;
223 : :
224 : : // set advanced config
225 : 13 : if ( mProject )
226 : : {
227 : 13 : mIndividualLayerSettings = QHash<QgsVectorLayer *, IndividualLayerSettings>();
228 : 13 : const auto constMapLayers = mProject->mapLayers();
229 : 13 : for ( QgsMapLayer *ml : constMapLayers )
230 : 0 : {
231 : 0 : QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
232 : 0 : if ( vl )
233 : : {
234 : 0 : mIndividualLayerSettings.insert( vl, IndividualLayerSettings( enabled, type, tolerance, units, 0.0, 0.0 ) );
235 : 0 : }
236 : : }
237 : 13 : }
238 : 13 : }
239 : :
240 : 0 : bool QgsSnappingConfig::enabled() const
241 : : {
242 : 0 : return mEnabled;
243 : : }
244 : :
245 : 0 : void QgsSnappingConfig::setEnabled( bool enabled )
246 : : {
247 : 0 : if ( mEnabled == enabled )
248 : : {
249 : 0 : return;
250 : : }
251 : 0 : mEnabled = enabled;
252 : 0 : }
253 : :
254 : 0 : QgsSnappingConfig::SnappingMode QgsSnappingConfig::mode() const
255 : : {
256 : 0 : return mMode;
257 : : }
258 : :
259 : 0 : void QgsSnappingConfig::setMode( QgsSnappingConfig::SnappingMode mode )
260 : : {
261 : 0 : if ( mMode == mode )
262 : : {
263 : 0 : return;
264 : : }
265 : 0 : mMode = mode;
266 : 0 : }
267 : :
268 : 0 : QgsSnappingConfig::SnappingTypeFlag QgsSnappingConfig::typeFlag() const
269 : : {
270 : 0 : return mType;
271 : : }
272 : :
273 : 0 : QgsSnappingConfig::SnappingType QgsSnappingConfig::type() const
274 : : {
275 : 0 : if ( ( mType & SegmentFlag ) && ( mType & VertexFlag ) )
276 : 0 : return QgsSnappingConfig::SnappingType::VertexAndSegment;
277 : 0 : else if ( mType & SegmentFlag )
278 : 0 : return QgsSnappingConfig::SnappingType::Segment;
279 : : else
280 : 0 : return QgsSnappingConfig::SnappingType::Vertex;
281 : 0 : }
282 : :
283 : 0 : QString QgsSnappingConfig::snappingTypeFlagToString( SnappingTypeFlag type )
284 : : {
285 : 0 : switch ( type )
286 : : {
287 : : case QgsSnappingConfig::NoSnapFlag:
288 : 0 : return QObject::tr( "No Snapping" );
289 : : case QgsSnappingConfig::VertexFlag:
290 : 0 : return QObject::tr( "Vertex" );
291 : : case QgsSnappingConfig::SegmentFlag:
292 : 0 : return QObject::tr( "Segment" );
293 : : case QgsSnappingConfig::AreaFlag:
294 : 0 : return QObject::tr( "Area" );
295 : : case QgsSnappingConfig::CentroidFlag:
296 : 0 : return QObject::tr( "Centroid" );
297 : : case QgsSnappingConfig::MiddleOfSegmentFlag:
298 : 0 : return QObject::tr( "Middle of Segments" );
299 : : case QgsSnappingConfig::LineEndpointFlag:
300 : 0 : return QObject::tr( "Line Endpoints" );
301 : : }
302 : 0 : return QString();
303 : 0 : }
304 : :
305 : 0 : QIcon QgsSnappingConfig::snappingTypeFlagToIcon( SnappingTypeFlag type )
306 : : {
307 : 0 : switch ( type )
308 : : {
309 : : case QgsSnappingConfig::NoSnapFlag:
310 : 0 : return QIcon();
311 : : case QgsSnappingConfig::VertexFlag:
312 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingVertex.svg" ) );
313 : : case QgsSnappingConfig::SegmentFlag:
314 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingSegment.svg" ) );
315 : : case QgsSnappingConfig::AreaFlag:
316 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingArea.svg" ) );
317 : : case QgsSnappingConfig::CentroidFlag:
318 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingCentroid.svg" ) );
319 : : case QgsSnappingConfig::MiddleOfSegmentFlag:
320 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingMiddle.svg" ) );
321 : : case QgsSnappingConfig::LineEndpointFlag:
322 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconSnappingEndpoint.svg" ) );
323 : : }
324 : 0 : return QIcon();
325 : 0 : }
326 : :
327 : 0 : void QgsSnappingConfig::setType( QgsSnappingConfig::SnappingType type )
328 : : {
329 : 0 : switch ( type )
330 : : {
331 : : case SnappingType::Vertex:
332 : 0 : mType = VertexFlag;
333 : 0 : break;
334 : : case SnappingType::VertexAndSegment:
335 : 0 : mType = static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag );
336 : 0 : break;
337 : : case SnappingType::Segment:
338 : 0 : mType = SegmentFlag;
339 : 0 : break;
340 : : default:
341 : 0 : mType = NoSnapFlag;
342 : 0 : break;
343 : : }
344 : 0 : }
345 : 0 : void QgsSnappingConfig::setTypeFlag( QgsSnappingConfig::SnappingTypeFlag type )
346 : : {
347 : 0 : if ( mType == type )
348 : : {
349 : 0 : return;
350 : : }
351 : 0 : mType = type;
352 : 0 : }
353 : :
354 : 0 : double QgsSnappingConfig::tolerance() const
355 : : {
356 : 0 : return mTolerance;
357 : : }
358 : :
359 : 0 : void QgsSnappingConfig::setTolerance( double tolerance )
360 : : {
361 : 0 : if ( mTolerance == tolerance )
362 : : {
363 : 0 : return;
364 : : }
365 : 0 : mTolerance = tolerance;
366 : 0 : }
367 : :
368 : 0 : QgsTolerance::UnitType QgsSnappingConfig::units() const
369 : : {
370 : 0 : return mUnits;
371 : : }
372 : :
373 : 0 : void QgsSnappingConfig::setUnits( QgsTolerance::UnitType units )
374 : : {
375 : 0 : if ( mUnits == units )
376 : : {
377 : 0 : return;
378 : : }
379 : 0 : mUnits = units;
380 : 0 : }
381 : :
382 : 0 : bool QgsSnappingConfig::intersectionSnapping() const
383 : : {
384 : 0 : return mIntersectionSnapping;
385 : : }
386 : :
387 : 0 : void QgsSnappingConfig::setIntersectionSnapping( bool enabled )
388 : : {
389 : 0 : mIntersectionSnapping = enabled;
390 : 0 : }
391 : :
392 : 0 : bool QgsSnappingConfig::selfSnapping() const
393 : : {
394 : 0 : return mSelfSnapping;
395 : : }
396 : :
397 : 0 : void QgsSnappingConfig::setSelfSnapping( bool enabled )
398 : : {
399 : 0 : mSelfSnapping = enabled;
400 : 0 : }
401 : :
402 : 0 : QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> QgsSnappingConfig::individualLayerSettings() const
403 : : {
404 : 0 : return mIndividualLayerSettings;
405 : : }
406 : :
407 : 0 : QgsSnappingConfig::IndividualLayerSettings QgsSnappingConfig::individualLayerSettings( QgsVectorLayer *vl ) const
408 : : {
409 : 0 : if ( vl && mIndividualLayerSettings.contains( vl ) )
410 : : {
411 : 0 : return mIndividualLayerSettings.value( vl );
412 : : }
413 : : else
414 : : {
415 : : // return invalid settings
416 : 0 : return IndividualLayerSettings();
417 : : }
418 : 0 : }
419 : :
420 : 8 : void QgsSnappingConfig::clearIndividualLayerSettings()
421 : : {
422 : 8 : mIndividualLayerSettings.clear();
423 : 8 : }
424 : :
425 : 0 : void QgsSnappingConfig::setIndividualLayerSettings( QgsVectorLayer *vl, const IndividualLayerSettings &individualLayerSettings )
426 : : {
427 : 0 : if ( !vl || !vl->isSpatial() || mIndividualLayerSettings.value( vl ) == individualLayerSettings )
428 : : {
429 : 0 : return;
430 : : }
431 : 0 : mIndividualLayerSettings.insert( vl, individualLayerSettings );
432 : 0 : }
433 : :
434 : 0 : bool QgsSnappingConfig::operator!=( const QgsSnappingConfig &other ) const
435 : : {
436 : 0 : return mEnabled != other.mEnabled
437 : 0 : || mMode != other.mMode
438 : 0 : || mType != other.mType
439 : 0 : || mTolerance != other.mTolerance
440 : 0 : || mUnits != other.mUnits
441 : 0 : || mIndividualLayerSettings != other.mIndividualLayerSettings
442 : 0 : || mScaleDependencyMode != other.mScaleDependencyMode
443 : 0 : || mMinimumScale != other.mMinimumScale
444 : 0 : || mMaximumScale != other.mMaximumScale;
445 : : }
446 : :
447 : 0 : void QgsSnappingConfig::readProject( const QDomDocument &doc )
448 : : {
449 : 0 : QDomElement snapSettingsElem = doc.firstChildElement( QStringLiteral( "qgis" ) ).firstChildElement( QStringLiteral( "snapping-settings" ) );
450 : 0 : if ( snapSettingsElem.isNull() )
451 : : {
452 : 0 : readLegacySettings();
453 : 0 : return;
454 : : }
455 : :
456 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "enabled" ) ) )
457 : 0 : mEnabled = snapSettingsElem.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "1" );
458 : :
459 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "mode" ) ) )
460 : 0 : mMode = static_cast< SnappingMode >( snapSettingsElem.attribute( QStringLiteral( "mode" ) ).toInt() );
461 : :
462 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "type" ) ) )
463 : : {
464 : 0 : int type = snapSettingsElem.attribute( QStringLiteral( "type" ) ).toInt();
465 : 0 : QDomElement versionElem = doc.firstChildElement( QStringLiteral( "qgis" ) );
466 : 0 : QString version;
467 : 0 : bool before3_14 = false;
468 : 0 : if ( versionElem.hasAttribute( QStringLiteral( "version" ) ) )
469 : 5 : {
470 : 5 : version = versionElem.attribute( QStringLiteral( "version" ) );
471 : 5 : QRegularExpression re( QStringLiteral( "([\\d]+)\\.([\\d]+)" ) );
472 : 5 : QRegularExpressionMatch match = re.match( version );
473 : 5 : if ( match.hasMatch() )
474 : 5 : {
475 : 5 : if ( ( match.captured( 1 ).toInt() <= 3 ) && ( match.captured( 2 ).toInt() <= 12 ) )
476 : 5 : before3_14 = true;
477 : 5 : }
478 : 5 : }
479 : 0 : if ( before3_14 )
480 : : {
481 : : // BEFORE 3.12:
482 : : // 1 = vertex
483 : : // 2 = vertexandsegment
484 : : // 3 = segment
485 : 0 : switch ( type )
486 : : {
487 : : case 1:
488 : 0 : mType = VertexFlag;
489 : 0 : break;
490 : : case 2:
491 : 0 : mType = static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag );
492 : 0 : break;
493 : : case 3:
494 : 0 : mType = SegmentFlag;
495 : 0 : break;
496 : : default:
497 : 0 : mType = NoSnapFlag;
498 : 0 : break;
499 : : }
500 : 0 : }
501 : : else
502 : 0 : mType = static_cast<QgsSnappingConfig::SnappingTypeFlag>( type );
503 : 0 : }
504 : :
505 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "tolerance" ) ) )
506 : 0 : mTolerance = snapSettingsElem.attribute( QStringLiteral( "tolerance" ) ).toDouble();
507 : :
508 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "scaleDependencyMode" ) ) )
509 : 0 : mScaleDependencyMode = static_cast<QgsSnappingConfig::ScaleDependencyMode>( snapSettingsElem.attribute( QStringLiteral( "scaleDependencyMode" ) ).toInt() );
510 : :
511 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "minScale" ) ) )
512 : 0 : mMinimumScale = snapSettingsElem.attribute( QStringLiteral( "minScale" ) ).toDouble();
513 : :
514 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "maxScale" ) ) )
515 : 0 : mMaximumScale = snapSettingsElem.attribute( QStringLiteral( "maxScale" ) ).toDouble();
516 : :
517 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "unit" ) ) )
518 : 0 : mUnits = static_cast< QgsTolerance::UnitType >( snapSettingsElem.attribute( QStringLiteral( "unit" ) ).toInt() );
519 : :
520 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "intersection-snapping" ) ) )
521 : 0 : mIntersectionSnapping = snapSettingsElem.attribute( QStringLiteral( "intersection-snapping" ) ) == QLatin1String( "1" );
522 : :
523 : 0 : if ( snapSettingsElem.hasAttribute( QStringLiteral( "self-snapping" ) ) )
524 : 0 : mSelfSnapping = snapSettingsElem.attribute( QStringLiteral( "self-snapping" ) ) == QLatin1String( "1" );
525 : :
526 : : // do not clear the settings as they must be automatically synchronized with current layers
527 : 0 : QDomNodeList nodes = snapSettingsElem.elementsByTagName( QStringLiteral( "individual-layer-settings" ) );
528 : 0 : if ( nodes.count() )
529 : : {
530 : 0 : QDomNode node = nodes.item( 0 );
531 : 0 : QDomNodeList settingNodes = node.childNodes();
532 : 0 : int layerCount = settingNodes.count();
533 : 0 : for ( int i = 0; i < layerCount; ++i )
534 : : {
535 : 0 : QDomElement settingElement = settingNodes.at( i ).toElement();
536 : 0 : if ( settingElement.tagName() != QLatin1String( "layer-setting" ) )
537 : : {
538 : 0 : QgsLogger::warning( QApplication::translate( "QgsProjectSnappingSettings", "Cannot read individual settings. Unexpected tag '%1'" ).arg( settingElement.tagName() ) );
539 : 0 : continue;
540 : : }
541 : :
542 : 0 : QString layerId = settingElement.attribute( QStringLiteral( "id" ) );
543 : 0 : bool enabled = settingElement.attribute( QStringLiteral( "enabled" ) ) == QLatin1String( "1" );
544 : 0 : QgsSnappingConfig::SnappingTypeFlag type = static_cast<QgsSnappingConfig::SnappingTypeFlag>( settingElement.attribute( QStringLiteral( "type" ) ).toInt() );
545 : 0 : double tolerance = settingElement.attribute( QStringLiteral( "tolerance" ) ).toDouble();
546 : 0 : QgsTolerance::UnitType units = static_cast< QgsTolerance::UnitType >( settingElement.attribute( QStringLiteral( "units" ) ).toInt() );
547 : 0 : double minScale = settingElement.attribute( QStringLiteral( "minScale" ) ).toDouble();
548 : 0 : double maxScale = settingElement.attribute( QStringLiteral( "maxScale" ) ).toDouble();
549 : :
550 : 0 : QgsMapLayer *ml = mProject->mapLayer( layerId );
551 : 0 : if ( !ml || ml->type() != QgsMapLayerType::VectorLayer )
552 : 0 : continue;
553 : :
554 : 0 : QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
555 : :
556 : 0 : IndividualLayerSettings setting = IndividualLayerSettings( enabled, type, tolerance, units, minScale, maxScale );
557 : 0 : mIndividualLayerSettings.insert( vl, setting );
558 : 0 : }
559 : 0 : }
560 : 0 : }
561 : :
562 : 0 : void QgsSnappingConfig::writeProject( QDomDocument &doc )
563 : : {
564 : 0 : QDomElement snapSettingsElem = doc.createElement( QStringLiteral( "snapping-settings" ) );
565 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "enabled" ), QString::number( mEnabled ) );
566 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "mode" ), static_cast<int>( mMode ) );
567 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "type" ), static_cast<int>( mType ) );
568 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
569 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "unit" ), static_cast<int>( mUnits ) );
570 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "intersection-snapping" ), QString::number( mIntersectionSnapping ) );
571 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "self-snapping" ), QString::number( mSelfSnapping ) );
572 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "scaleDependencyMode" ), QString::number( mScaleDependencyMode ) );
573 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "minScale" ), mMinimumScale );
574 : 0 : snapSettingsElem.setAttribute( QStringLiteral( "maxScale" ), mMaximumScale );
575 : :
576 : 0 : QDomElement ilsElement = doc.createElement( QStringLiteral( "individual-layer-settings" ) );
577 : 0 : QHash<QgsVectorLayer *, IndividualLayerSettings>::const_iterator layerIt = mIndividualLayerSettings.constBegin();
578 : 0 : for ( ; layerIt != mIndividualLayerSettings.constEnd(); ++layerIt )
579 : : {
580 : 0 : const IndividualLayerSettings &setting = layerIt.value();
581 : :
582 : 0 : QDomElement layerElement = doc.createElement( QStringLiteral( "layer-setting" ) );
583 : 0 : layerElement.setAttribute( QStringLiteral( "id" ), layerIt.key()->id() );
584 : 0 : layerElement.setAttribute( QStringLiteral( "enabled" ), QString::number( setting.enabled() ) );
585 : 0 : layerElement.setAttribute( QStringLiteral( "type" ), static_cast<int>( setting.typeFlag() ) );
586 : 0 : layerElement.setAttribute( QStringLiteral( "tolerance" ), setting.tolerance() );
587 : 0 : layerElement.setAttribute( QStringLiteral( "units" ), static_cast<int>( setting.units() ) );
588 : 0 : layerElement.setAttribute( QStringLiteral( "minScale" ), setting.minimumScale() );
589 : 0 : layerElement.setAttribute( QStringLiteral( "maxScale" ), setting.maximumScale() );
590 : 0 : ilsElement.appendChild( layerElement );
591 : 0 : }
592 : 0 : snapSettingsElem.appendChild( ilsElement );
593 : :
594 : 0 : doc.firstChildElement( QStringLiteral( "qgis" ) ).appendChild( snapSettingsElem );
595 : 0 : }
596 : :
597 : 1 : bool QgsSnappingConfig::addLayers( const QList<QgsMapLayer *> &layers )
598 : : {
599 : 1 : bool changed = false;
600 : 2 : bool enabled = QgsSettings().value( QStringLiteral( "/qgis/digitizing/default_snap_enabled" ), true ).toBool();
601 : 2 : QgsSnappingConfig::SnappingTypeFlag type = QgsSettings().enumValue( QStringLiteral( "/qgis/digitizing/default_snap_type" ), VertexFlag );
602 : 2 : double tolerance = QgsSettings().value( QStringLiteral( "/qgis/digitizing/default_snapping_tolerance" ), Qgis::DEFAULT_SNAP_TOLERANCE ).toDouble();
603 : 2 : QgsTolerance::UnitType units = QgsSettings().enumValue( QStringLiteral( "/qgis/digitizing/default_snapping_tolerance_unit" ), Qgis::DEFAULT_SNAP_UNITS );
604 : :
605 : 1 : const auto constLayers = layers;
606 : 2 : for ( QgsMapLayer *ml : constLayers )
607 : : {
608 : 1 : QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
609 : 1 : if ( vl && vl->isSpatial() )
610 : : {
611 : 1 : mIndividualLayerSettings.insert( vl, IndividualLayerSettings( enabled, type, tolerance, units, 0.0, 0.0 ) );
612 : 1 : changed = true;
613 : 1 : }
614 : : }
615 : 1 : return changed;
616 : 1 : }
617 : :
618 : 0 : bool QgsSnappingConfig::removeLayers( const QList<QgsMapLayer *> &layers )
619 : : {
620 : 0 : bool changed = false;
621 : 0 : const auto constLayers = layers;
622 : 0 : for ( QgsMapLayer *ml : constLayers )
623 : : {
624 : 0 : QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml );
625 : 0 : if ( vl )
626 : : {
627 : 0 : mIndividualLayerSettings.remove( vl );
628 : 0 : changed = true;
629 : 0 : }
630 : : }
631 : 0 : return changed;
632 : 0 : }
633 : :
634 : 0 : void QgsSnappingConfig::readLegacySettings()
635 : : {
636 : : //
637 : 0 : mMode = ActiveLayer;
638 : :
639 : 0 : QString snapMode = mProject->readEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/SnappingMode" ) );
640 : :
641 : 0 : mTolerance = mProject->readDoubleEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/DefaultSnapTolerance" ), 0 );
642 : 0 : mUnits = static_cast< QgsTolerance::UnitType >( mProject->readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/DefaultSnapToleranceUnit" ), QgsTolerance::ProjectUnits ) );
643 : :
644 : 0 : mIntersectionSnapping = mProject->readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/IntersectionSnapping" ), 0 );
645 : :
646 : : //read snapping settings from project
647 : 0 : QStringList layerIdList = mProject->readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/LayerSnappingList" ), QStringList() );
648 : 0 : QStringList enabledList = mProject->readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/LayerSnappingEnabledList" ), QStringList() );
649 : 0 : QStringList toleranceList = mProject->readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/LayerSnappingToleranceList" ), QStringList() );
650 : 0 : QStringList toleranceUnitList = mProject->readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/LayerSnappingToleranceUnitList" ), QStringList() );
651 : 0 : QStringList snapToList = mProject->readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/LayerSnapToList" ), QStringList() );
652 : :
653 : : // lists must have the same size, otherwise something is wrong
654 : 0 : if ( layerIdList.size() != enabledList.size() ||
655 : 0 : layerIdList.size() != toleranceList.size() ||
656 : 0 : layerIdList.size() != toleranceUnitList.size() ||
657 : 0 : layerIdList.size() != snapToList.size() )
658 : 0 : return;
659 : :
660 : : // Use snapping information from the project
661 : 0 : if ( snapMode == QLatin1String( "current_layer" ) )
662 : 0 : mMode = ActiveLayer;
663 : 0 : else if ( snapMode == QLatin1String( "all_layers" ) )
664 : 0 : mMode = AllLayers;
665 : : else // either "advanced" or empty (for background compatibility)
666 : 0 : mMode = AdvancedConfiguration;
667 : :
668 : : // load layers, tolerances, snap type
669 : 0 : QStringList::const_iterator layerIt( layerIdList.constBegin() );
670 : 0 : QStringList::const_iterator tolIt( toleranceList.constBegin() );
671 : 0 : QStringList::const_iterator tolUnitIt( toleranceUnitList.constBegin() );
672 : 0 : QStringList::const_iterator snapIt( snapToList.constBegin() );
673 : 0 : QStringList::const_iterator enabledIt( enabledList.constBegin() );
674 : 0 : for ( ; layerIt != layerIdList.constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
675 : : {
676 : 0 : QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mProject->mapLayer( *layerIt ) );
677 : 0 : if ( !vlayer || !vlayer->isSpatial() )
678 : 0 : continue;
679 : :
680 : 0 : QgsSnappingConfig::SnappingTypeFlag t( *snapIt == QLatin1String( "to_vertex" ) ? VertexFlag :
681 : 0 : ( *snapIt == QLatin1String( "to_segment" ) ? SegmentFlag :
682 : 0 : static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag )
683 : : )
684 : : );
685 : :
686 : 0 : mIndividualLayerSettings.insert( vlayer, IndividualLayerSettings( *enabledIt == QLatin1String( "enabled" ), t, tolIt->toDouble(), static_cast<QgsTolerance::UnitType>( tolUnitIt->toInt() ), 0.0, 0.0 ) );
687 : 0 : }
688 : :
689 : 0 : QString snapType = mProject->readEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/DefaultSnapType" ), QStringLiteral( "off" ) );
690 : 0 : mEnabled = true;
691 : 0 : if ( snapType == QLatin1String( "to segment" ) )
692 : 0 : mType = SegmentFlag;
693 : 0 : else if ( snapType == QLatin1String( "to vertex and segment" ) )
694 : 0 : mType = static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag );
695 : 0 : else if ( snapType == QLatin1String( "to vertex" ) )
696 : 0 : mType = VertexFlag;
697 : 0 : else if ( mMode != AdvancedConfiguration ) // Type is off but mode is advanced
698 : : {
699 : 0 : mEnabled = false;
700 : 0 : }
701 : 0 : }
702 : :
703 : 0 : QgsProject *QgsSnappingConfig::project() const
704 : : {
705 : 0 : return mProject;
706 : : }
707 : :
708 : 0 : void QgsSnappingConfig::setProject( QgsProject *project )
709 : : {
710 : 0 : if ( mProject != project )
711 : 0 : mProject = project;
712 : :
713 : 0 : reset();
714 : 0 : }
715 : :
716 : 0 : double QgsSnappingConfig::minimumScale() const
717 : : {
718 : 0 : return mMinimumScale;
719 : : }
720 : :
721 : 0 : void QgsSnappingConfig::setMinimumScale( double minScale )
722 : : {
723 : 0 : mMinimumScale = minScale;
724 : 0 : }
725 : :
726 : 0 : double QgsSnappingConfig::maximumScale() const
727 : : {
728 : 0 : return mMaximumScale;
729 : : }
730 : :
731 : 0 : void QgsSnappingConfig::setMaximumScale( double maxScale )
732 : : {
733 : 0 : mMaximumScale = maxScale;
734 : 0 : }
735 : :
736 : 0 : void QgsSnappingConfig::setScaleDependencyMode( QgsSnappingConfig::ScaleDependencyMode mode )
737 : : {
738 : 0 : mScaleDependencyMode = mode;
739 : 0 : }
740 : :
741 : 0 : QgsSnappingConfig::ScaleDependencyMode QgsSnappingConfig::scaleDependencyMode() const
742 : : {
743 : 0 : return mScaleDependencyMode;
744 : : }
745 : :
746 : :
747 : :
748 : :
749 : :
|