18 #include <QDomElement> 
   19 #include <QHeaderView> 
   20 #include <QRegularExpression> 
   33   , mTolerance( tolerance )
 
   35   , mMinimumScale( minScale )
 
   36   , mMaximumScale( maxScale )
 
   73   if ( ( mType & QgsSnappingConfig::SnappingType::Segment ) && ( mType & QgsSnappingConfig::SnappingType::Vertex ) )
 
   74     return QgsSnappingConfig::SnappingType::VertexAndSegment;
 
   75   else if ( mType & QgsSnappingConfig::SnappingType::Segment )
 
   76     return QgsSnappingConfig::SnappingType::Segment;
 
   78     return QgsSnappingConfig::SnappingType::Vertex;
 
   87       mType = Qgis::SnappingType::Vertex;
 
   90       mType = Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment;
 
   93       mType = Qgis::SnappingType::Segment;
 
   96       mType = Qgis::SnappingType::NoSnap;
 
  127   return mMinimumScale;
 
  132   mMinimumScale = minScale;
 
  137   return mMaximumScale;
 
  142   mMaximumScale = maxScale;
 
  147   return mValid != other.mValid
 
  148          || mEnabled != other.mEnabled
 
  149          || mType != other.mType
 
  150          || mTolerance != other.mTolerance
 
  151          || mUnits != other.mUnits
 
  152          || mMinimumScale != other.mMinimumScale
 
  153          || mMaximumScale != other.mMaximumScale;
 
  158   return mValid == other.mValid
 
  159          && mEnabled == other.mEnabled
 
  160          && mType == other.mType
 
  161          && mTolerance == other.mTolerance
 
  162          && mUnits == other.mUnits
 
  163          && mMinimumScale == other.mMinimumScale
 
  164          && mMaximumScale == other.mMaximumScale;
 
  176   return mEnabled == other.mEnabled
 
  177          && mMode == other.mMode
 
  178          && mType == other.mType
 
  179          && mTolerance == other.mTolerance
 
  180          && mUnits == other.mUnits
 
  181          && mIntersectionSnapping == other.mIntersectionSnapping
 
  182          && mSelfSnapping == other.mSelfSnapping
 
  183          && mIndividualLayerSettings == other.mIndividualLayerSettings
 
  184          && mScaleDependencyMode == other.mScaleDependencyMode
 
  185          && mMinimumScale == other.mMinimumScale
 
  186          && mMaximumScale == other.mMaximumScale;
 
  215   mIntersectionSnapping = 
false;
 
  216   mSelfSnapping = 
false;
 
  221     mIndividualLayerSettings = QHash<QgsVectorLayer *, IndividualLayerSettings>();
 
  222     const auto constMapLayers = mProject->
mapLayers();
 
  269   if ( ( mType & QgsSnappingConfig::SnappingType::Segment ) && ( mType & QgsSnappingConfig::SnappingType::Vertex ) )
 
  270     return QgsSnappingConfig::SnappingType::VertexAndSegment;
 
  271   else if ( mType & QgsSnappingConfig::SnappingType::Segment )
 
  272     return QgsSnappingConfig::SnappingType::Segment;
 
  274     return QgsSnappingConfig::SnappingType::Vertex;
 
  281     case Qgis::SnappingType::NoSnap:
 
  282       return QObject::tr( 
"No Snapping" );
 
  283     case Qgis::SnappingType::Vertex:
 
  284       return QObject::tr( 
"Vertex" );
 
  285     case Qgis::SnappingType::Segment:
 
  286       return QObject::tr( 
"Segment" );
 
  287     case Qgis::SnappingType::Area:
 
  288       return QObject::tr( 
"Area" );
 
  289     case Qgis::SnappingType::Centroid:
 
  290       return QObject::tr( 
"Centroid" );
 
  291     case Qgis::SnappingType::MiddleOfSegment:
 
  292       return QObject::tr( 
"Middle of Segments" );
 
  293     case Qgis::SnappingType::LineEndpoint:
 
  294       return QObject::tr( 
"Line Endpoints" );
 
  303     case Qgis::SnappingType::NoSnap:
 
  305     case Qgis::SnappingType::Vertex:
 
  307     case Qgis::SnappingType::Segment:
 
  309     case Qgis::SnappingType::Area:
 
  311     case Qgis::SnappingType::Centroid:
 
  313     case Qgis::SnappingType::MiddleOfSegment:
 
  315     case Qgis::SnappingType::LineEndpoint:
 
  325     case SnappingType::Vertex:
 
  326       mType = Qgis::SnappingType::Vertex;
 
  328     case SnappingType::VertexAndSegment:
 
  329       mType = 
static_cast<Qgis::SnappingTypes
>( Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment );
 
  331     case SnappingType::Segment:
 
  332       mType = Qgis::SnappingType::Segment;
 
  335       mType = Qgis::SnappingType::NoSnap;
 
  369   if ( mUnits == 
units )
 
  378   return mIntersectionSnapping;
 
  383   mIntersectionSnapping = 
enabled;
 
  388   return mSelfSnapping;
 
  398   return mIndividualLayerSettings;
 
  403   if ( vl && mIndividualLayerSettings.contains( vl ) )
 
  405     return mIndividualLayerSettings.value( vl );
 
  416   mIndividualLayerSettings.clear();
 
  430   return mEnabled != other.mEnabled
 
  431          || mMode != other.mMode
 
  432          || mType != other.mType
 
  433          || mTolerance != other.mTolerance
 
  434          || mUnits != other.mUnits
 
  435          || mIndividualLayerSettings != other.mIndividualLayerSettings
 
  436          || mScaleDependencyMode != other.mScaleDependencyMode
 
  437          || mMinimumScale != other.mMinimumScale
 
  438          || mMaximumScale != other.mMaximumScale;
 
  443   const QDomElement snapSettingsElem = doc.firstChildElement( QStringLiteral( 
"qgis" ) ).firstChildElement( QStringLiteral( 
"snapping-settings" ) );
 
  444   if ( snapSettingsElem.isNull() )
 
  446     readLegacySettings();
 
  450   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"enabled" ) ) )
 
  451     mEnabled = snapSettingsElem.attribute( QStringLiteral( 
"enabled" ) ) == QLatin1String( 
"1" );
 
  453   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"mode" ) ) )
 
  454     mMode = 
static_cast< Qgis::SnappingMode >( snapSettingsElem.attribute( QStringLiteral( 
"mode" ) ).toInt() );
 
  456   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"type" ) ) )
 
  458     const int type = snapSettingsElem.attribute( QStringLiteral( 
"type" ) ).toInt();
 
  459     const QDomElement versionElem = doc.firstChildElement( QStringLiteral( 
"qgis" ) );
 
  461     bool before3_14 = 
false;
 
  462     if ( versionElem.hasAttribute( QStringLiteral( 
"version" ) ) )
 
  464       version = versionElem.attribute( QStringLiteral( 
"version" ) );
 
  465       const QRegularExpression re( QStringLiteral( 
"([\\d]+)\\.([\\d]+)" ) );
 
  466       const QRegularExpressionMatch match = re.match( version );
 
  467       if ( match.hasMatch() )
 
  469         if ( ( match.captured( 1 ).toInt() <= 3 ) && ( match.captured( 2 ).toInt() <= 12 ) )
 
  482           mType = Qgis::SnappingType::Vertex;
 
  485           mType = 
static_cast<Qgis::SnappingTypes
>( Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment );
 
  488           mType = Qgis::SnappingType::Segment;
 
  491           mType = Qgis::SnappingType::NoSnap;
 
  496       mType = 
static_cast<Qgis::SnappingTypes
>( 
type );
 
  499   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"tolerance" ) ) )
 
  500     mTolerance = snapSettingsElem.attribute( QStringLiteral( 
"tolerance" ) ).toDouble();
 
  502   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"scaleDependencyMode" ) ) )
 
  505   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"minScale" ) ) )
 
  506     mMinimumScale = snapSettingsElem.attribute( QStringLiteral( 
"minScale" ) ).toDouble();
 
  508   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"maxScale" ) ) )
 
  509     mMaximumScale = snapSettingsElem.attribute( QStringLiteral( 
"maxScale" ) ).toDouble();
 
  511   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"unit" ) ) )
 
  512     mUnits = 
static_cast< QgsTolerance::UnitType >( snapSettingsElem.attribute( QStringLiteral( 
"unit" ) ).toInt() );
 
  514   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"intersection-snapping" ) ) )
 
  515     mIntersectionSnapping = snapSettingsElem.attribute( QStringLiteral( 
"intersection-snapping" ) ) == QLatin1String( 
"1" );
 
  517   if ( snapSettingsElem.hasAttribute( QStringLiteral( 
"self-snapping" ) ) )
 
  518     mSelfSnapping = snapSettingsElem.attribute( QStringLiteral( 
"self-snapping" ) ) == QLatin1String( 
"1" );
 
  521   const QDomNodeList nodes = snapSettingsElem.elementsByTagName( QStringLiteral( 
"individual-layer-settings" ) );
 
  524     const QDomNode node = nodes.item( 0 );
 
  525     const QDomNodeList settingNodes = node.childNodes();
 
  526     const int layerCount = settingNodes.count();
 
  527     for ( 
int i = 0; i < layerCount; ++i )
 
  529       const QDomElement settingElement = settingNodes.at( i ).toElement();
 
  530       if ( settingElement.tagName() != QLatin1String( 
"layer-setting" ) )
 
  532         QgsLogger::warning( QApplication::translate( 
"QgsProjectSnappingSettings", 
"Cannot read individual settings. Unexpected tag '%1'" ).arg( settingElement.tagName() ) );
 
  536       const QString layerId = settingElement.attribute( QStringLiteral( 
"id" ) );
 
  537       const bool enabled = settingElement.attribute( QStringLiteral( 
"enabled" ) ) == QLatin1String( 
"1" );
 
  538       const Qgis::SnappingTypes 
type = 
static_cast<Qgis::SnappingTypes
>( settingElement.attribute( QStringLiteral( 
"type" ) ).toInt() );
 
  539       const double tolerance = settingElement.attribute( QStringLiteral( 
"tolerance" ) ).toDouble();
 
  541       const double minScale = settingElement.attribute( QStringLiteral( 
"minScale" ) ).toDouble();
 
  542       const double maxScale = settingElement.attribute( QStringLiteral( 
"maxScale" ) ).toDouble();
 
  551       mIndividualLayerSettings.insert( vl, setting );
 
  558   QDomElement snapSettingsElem = doc.createElement( QStringLiteral( 
"snapping-settings" ) );
 
  559   snapSettingsElem.setAttribute( QStringLiteral( 
"enabled" ), QString::number( mEnabled ) );
 
  560   snapSettingsElem.setAttribute( QStringLiteral( 
"mode" ), 
static_cast<int>( mMode ) );
 
  561   snapSettingsElem.setAttribute( QStringLiteral( 
"type" ), 
static_cast<int>( mType ) );
 
  562   snapSettingsElem.setAttribute( QStringLiteral( 
"tolerance" ), mTolerance );
 
  563   snapSettingsElem.setAttribute( QStringLiteral( 
"unit" ), 
static_cast<int>( mUnits ) );
 
  564   snapSettingsElem.setAttribute( QStringLiteral( 
"intersection-snapping" ), QString::number( mIntersectionSnapping ) );
 
  565   snapSettingsElem.setAttribute( QStringLiteral( 
"self-snapping" ), QString::number( mSelfSnapping ) );
 
  566   snapSettingsElem.setAttribute( QStringLiteral( 
"scaleDependencyMode" ), QString::number( mScaleDependencyMode ) );
 
  567   snapSettingsElem.setAttribute( QStringLiteral( 
"minScale" ), mMinimumScale );
 
  568   snapSettingsElem.setAttribute( QStringLiteral( 
"maxScale" ), mMaximumScale );
 
  570   QDomElement ilsElement = doc.createElement( QStringLiteral( 
"individual-layer-settings" ) );
 
  571   QHash<QgsVectorLayer *, IndividualLayerSettings>::const_iterator layerIt = mIndividualLayerSettings.constBegin();
 
  572   for ( ; layerIt != mIndividualLayerSettings.constEnd(); ++layerIt )
 
  576     QDomElement layerElement = doc.createElement( QStringLiteral( 
"layer-setting" ) );
 
  577     layerElement.setAttribute( QStringLiteral( 
"id" ), layerIt.key()->id() );
 
  578     layerElement.setAttribute( QStringLiteral( 
"enabled" ), QString::number( setting.
enabled() ) );
 
  579     layerElement.setAttribute( QStringLiteral( 
"type" ), 
static_cast<int>( setting.
typeFlag() ) );
 
  580     layerElement.setAttribute( QStringLiteral( 
"tolerance" ), setting.
tolerance() );
 
  581     layerElement.setAttribute( QStringLiteral( 
"units" ), 
static_cast<int>( setting.
units() ) );
 
  582     layerElement.setAttribute( QStringLiteral( 
"minScale" ), setting.
minimumScale() );
 
  583     layerElement.setAttribute( QStringLiteral( 
"maxScale" ), setting.
maximumScale() );
 
  584     ilsElement.appendChild( layerElement );
 
  586   snapSettingsElem.appendChild( ilsElement );
 
  588   doc.firstChildElement( QStringLiteral( 
"qgis" ) ).appendChild( snapSettingsElem );
 
  593   bool changed = 
false;
 
  599   const auto constLayers = layers;
 
  614   bool changed = 
false;
 
  615   const auto constLayers = layers;
 
  621       mIndividualLayerSettings.remove( vl );
 
  628 void QgsSnappingConfig::readLegacySettings()
 
  633   const QString snapMode = mProject->
readEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/SnappingMode" ) );
 
  635   mTolerance = mProject->
readDoubleEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/DefaultSnapTolerance" ), 0 );
 
  638   mIntersectionSnapping = mProject->
readNumEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/IntersectionSnapping" ), 0 );
 
  641   const QStringList layerIdList = mProject->
readListEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/LayerSnappingList" ), QStringList() );
 
  642   const QStringList enabledList = mProject->
readListEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/LayerSnappingEnabledList" ), QStringList() );
 
  643   const QStringList toleranceList = mProject->
readListEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/LayerSnappingToleranceList" ), QStringList() );
 
  644   const QStringList toleranceUnitList = mProject->
readListEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/LayerSnappingToleranceUnitList" ), QStringList() );
 
  645   const QStringList snapToList = mProject->
readListEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/LayerSnapToList" ), QStringList() );
 
  648   if ( layerIdList.size() != enabledList.size() ||
 
  649        layerIdList.size() != toleranceList.size() ||
 
  650        layerIdList.size() != toleranceUnitList.size() ||
 
  651        layerIdList.size() != snapToList.size() )
 
  655   if ( snapMode == QLatin1String( 
"current_layer" ) )
 
  657   else if ( snapMode == QLatin1String( 
"all_layers" ) )
 
  663   QStringList::const_iterator layerIt( layerIdList.constBegin() );
 
  664   QStringList::const_iterator tolIt( toleranceList.constBegin() );
 
  665   QStringList::const_iterator tolUnitIt( toleranceUnitList.constBegin() );
 
  666   QStringList::const_iterator snapIt( snapToList.constBegin() );
 
  667   QStringList::const_iterator enabledIt( enabledList.constBegin() );
 
  668   for ( ; layerIt != layerIdList.constEnd(); ++layerIt, ++tolIt, ++tolUnitIt, ++snapIt, ++enabledIt )
 
  674     const Qgis::SnappingTypes t( *snapIt == QLatin1String( 
"to_vertex" ) ? Qgis::SnappingType::Vertex :
 
  675                                  ( *snapIt == QLatin1String( 
"to_segment" ) ? Qgis::SnappingType::Segment :
 
  676                                    static_cast<Qgis::SnappingTypes
>( Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment )
 
  680     mIndividualLayerSettings.insert( vlayer, IndividualLayerSettings( *enabledIt == QLatin1String( 
"enabled" ), t, tolIt->toDouble(), 
static_cast<QgsTolerance::UnitType>( tolUnitIt->toInt() ), 0.0, 0.0 ) );
 
  683   const QString snapType = mProject->
readEntry( QStringLiteral( 
"Digitizing" ), QStringLiteral( 
"/DefaultSnapType" ), QStringLiteral( 
"off" ) );
 
  685   if ( snapType == QLatin1String( 
"to segment" ) )
 
  686     mType = Qgis::SnappingType::Segment;
 
  687   else if ( snapType == QLatin1String( 
"to vertex and segment" ) )
 
  688     mType = 
static_cast<Qgis::SnappingTypes
>( Qgis::SnappingType::Vertex | Qgis::SnappingType::Segment );
 
  689   else if ( snapType == QLatin1String( 
"to vertex" ) )
 
  690     mType = Qgis::SnappingType::Vertex;
 
  712   return mMinimumScale;
 
  717   mMinimumScale = minScale;
 
  722   return mMaximumScale;
 
  727   mMaximumScale = maxScale;
 
  732   mScaleDependencyMode = 
mode;
 
  737   return mScaleDependencyMode;