Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsprocessingcontext.cpp 3 : : ---------------------- 4 : : begin : April 2017 5 : : copyright : (C) 2017 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgsprocessingcontext.h" 19 : : #include "qgsprocessingutils.h" 20 : : #include "qgsproviderregistry.h" 21 : : #include "qgssettings.h" 22 : : 23 : 0 : QgsProcessingContext::QgsProcessingContext() 24 : 0 : : mPreferredVectorFormat( QgsProcessingUtils::defaultVectorExtension() ) 25 : 0 : , mPreferredRasterFormat( QgsProcessingUtils::defaultRasterExtension() ) 26 : : { 27 : 0 : auto callback = [ = ]( const QgsFeature & feature ) 28 : : { 29 : 0 : if ( mFeedback ) 30 : 0 : mFeedback->reportError( QObject::tr( "Encountered a transform error when reprojecting feature with id %1." ).arg( feature.id() ) ); 31 : 0 : }; 32 : 0 : mTransformErrorCallback = callback; 33 : 0 : } 34 : : 35 : 0 : QgsProcessingContext::~QgsProcessingContext() 36 : : { 37 : 0 : for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it ) 38 : : { 39 : 0 : delete it.value().postProcessor(); 40 : 0 : } 41 : 0 : } 42 : : 43 : 0 : void QgsProcessingContext::setLayersToLoadOnCompletion( const QMap<QString, QgsProcessingContext::LayerDetails> &layers ) 44 : : { 45 : 0 : for ( auto it = mLayersToLoadOnCompletion.constBegin(); it != mLayersToLoadOnCompletion.constEnd(); ++it ) 46 : : { 47 : 0 : if ( !layers.contains( it.key() ) || layers.value( it.key() ).postProcessor() != it.value().postProcessor() ) 48 : 0 : delete it.value().postProcessor(); 49 : 0 : } 50 : 0 : mLayersToLoadOnCompletion = layers; 51 : 0 : } 52 : : 53 : 0 : void QgsProcessingContext::addLayerToLoadOnCompletion( const QString &layer, const QgsProcessingContext::LayerDetails &details ) 54 : : { 55 : 0 : if ( mLayersToLoadOnCompletion.contains( layer ) && mLayersToLoadOnCompletion.value( layer ).postProcessor() != details.postProcessor() ) 56 : 0 : delete mLayersToLoadOnCompletion.value( layer ).postProcessor(); 57 : : 58 : 0 : mLayersToLoadOnCompletion.insert( layer, details ); 59 : 0 : } 60 : : 61 : 0 : void QgsProcessingContext::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check ) 62 : : { 63 : 0 : mInvalidGeometryCheck = check; 64 : 0 : mUseDefaultInvalidGeometryCallback = true; 65 : 0 : mInvalidGeometryCallback = defaultInvalidGeometryCallbackForCheck( check ); 66 : 0 : } 67 : : 68 : 0 : std::function<void ( const QgsFeature & )> QgsProcessingContext::invalidGeometryCallback( QgsFeatureSource *source ) const 69 : : { 70 : 0 : if ( mUseDefaultInvalidGeometryCallback ) 71 : 0 : return defaultInvalidGeometryCallbackForCheck( mInvalidGeometryCheck, source ); 72 : : else 73 : 0 : return mInvalidGeometryCallback; 74 : 0 : } 75 : : 76 : 0 : std::function<void ( const QgsFeature & )> QgsProcessingContext::defaultInvalidGeometryCallbackForCheck( QgsFeatureRequest::InvalidGeometryCheck check, QgsFeatureSource *source ) const 77 : : { 78 : 0 : const QString sourceName = source ? source->sourceName() : QString(); 79 : 0 : switch ( check ) 80 : : { 81 : : case QgsFeatureRequest::GeometryAbortOnInvalid: 82 : : { 83 : 0 : auto callback = [sourceName]( const QgsFeature & feature ) 84 : : { 85 : 0 : if ( !sourceName.isEmpty() ) 86 : 0 : throw QgsProcessingException( QObject::tr( "Feature (%1) from “%2” has invalid geometry. Please fix the geometry or change the Processing setting to the “Ignore invalid input features” option." ).arg( feature.id() ).arg( sourceName ) ); 87 : : else 88 : 0 : throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the “Ignore invalid input features” option." ).arg( feature.id() ) ); 89 : 0 : }; 90 : 0 : return callback; 91 : 0 : } 92 : : 93 : : case QgsFeatureRequest::GeometrySkipInvalid: 94 : : { 95 : 0 : auto callback = [ = ]( const QgsFeature & feature ) 96 : : { 97 : 0 : if ( mFeedback ) 98 : : { 99 : 0 : if ( !sourceName.isEmpty() ) 100 : 0 : mFeedback->reportError( QObject::tr( "Feature (%1) from “%2” has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the “Ignore invalid input features” option." ).arg( feature.id() ).arg( sourceName ) ); 101 : : else 102 : 0 : mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the “Ignore invalid input features” option." ).arg( feature.id() ) ); 103 : 0 : } 104 : 0 : }; 105 : 0 : return callback; 106 : 0 : } 107 : : 108 : : case QgsFeatureRequest::GeometryNoCheck: 109 : 0 : return nullptr; 110 : : } 111 : 0 : return nullptr; 112 : 0 : } 113 : : 114 : 0 : void QgsProcessingContext::takeResultsFrom( QgsProcessingContext &context ) 115 : : { 116 : 0 : setLayersToLoadOnCompletion( context.mLayersToLoadOnCompletion ); 117 : 0 : context.mLayersToLoadOnCompletion.clear(); 118 : 0 : tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() ); 119 : 0 : } 120 : : 121 : 0 : QgsMapLayer *QgsProcessingContext::getMapLayer( const QString &identifier ) 122 : : { 123 : 0 : return QgsProcessingUtils::mapLayerFromString( identifier, *this, false ); 124 : : } 125 : : 126 : 0 : QgsMapLayer *QgsProcessingContext::takeResultLayer( const QString &id ) 127 : : { 128 : 0 : return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) ); 129 : : } 130 : : 131 : 0 : QgsProcessingContext::LogLevel QgsProcessingContext::logLevel() const 132 : : { 133 : 0 : return mLogLevel; 134 : : } 135 : : 136 : 0 : void QgsProcessingContext::setLogLevel( LogLevel level ) 137 : : { 138 : 0 : mLogLevel = level; 139 : 0 : } 140 : : 141 : 0 : QgsDateTimeRange QgsProcessingContext::currentTimeRange() const 142 : : { 143 : 0 : return mCurrentTimeRange; 144 : : } 145 : : 146 : 0 : void QgsProcessingContext::setCurrentTimeRange( const QgsDateTimeRange ¤tTimeRange ) 147 : : { 148 : 0 : mCurrentTimeRange = currentTimeRange; 149 : 0 : } 150 : : 151 : 0 : QString QgsProcessingContext::ellipsoid() const 152 : : { 153 : 0 : return mEllipsoid; 154 : : } 155 : : 156 : 0 : void QgsProcessingContext::setEllipsoid( const QString &ellipsoid ) 157 : : { 158 : 0 : mEllipsoid = ellipsoid; 159 : 0 : } 160 : : 161 : 0 : QgsUnitTypes::DistanceUnit QgsProcessingContext::distanceUnit() const 162 : : { 163 : 0 : return mDistanceUnit; 164 : : } 165 : : 166 : 0 : void QgsProcessingContext::setDistanceUnit( QgsUnitTypes::DistanceUnit unit ) 167 : : { 168 : 0 : mDistanceUnit = unit; 169 : 0 : } 170 : : 171 : 0 : QgsUnitTypes::AreaUnit QgsProcessingContext::areaUnit() const 172 : : { 173 : 0 : return mAreaUnit; 174 : : } 175 : : 176 : 0 : void QgsProcessingContext::setAreaUnit( QgsUnitTypes::AreaUnit areaUnit ) 177 : : { 178 : 0 : mAreaUnit = areaUnit; 179 : 0 : } 180 : : 181 : 0 : QgsProcessingLayerPostProcessorInterface *QgsProcessingContext::LayerDetails::postProcessor() const 182 : : { 183 : 0 : return mPostProcessor; 184 : : } 185 : : 186 : 0 : void QgsProcessingContext::LayerDetails::setPostProcessor( QgsProcessingLayerPostProcessorInterface *processor ) 187 : : { 188 : 0 : if ( mPostProcessor && mPostProcessor != processor ) 189 : 0 : delete mPostProcessor; 190 : : 191 : 0 : mPostProcessor = processor; 192 : 0 : } 193 : : 194 : 0 : void QgsProcessingContext::LayerDetails::setOutputLayerName( QgsMapLayer *layer ) const 195 : : { 196 : 0 : if ( !layer ) 197 : 0 : return; 198 : : 199 : 0 : const bool preferFilenameAsLayerName = QgsSettings().value( QStringLiteral( "Processing/Configuration/PREFER_FILENAME_AS_LAYER_NAME" ), true ).toBool(); 200 : : 201 : : // note - for temporary layers, we don't use the filename, regardless of user setting (it will be meaningless!) 202 : 0 : if ( ( !forceName && preferFilenameAsLayerName && !layer->isTemporary() ) || name.isEmpty() ) 203 : : { 204 : 0 : const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() ); 205 : 0 : const QString layerName = sourceParts.value( QStringLiteral( "layerName" ) ).toString(); 206 : : // if output layer name exists, use that! 207 : 0 : if ( !layerName.isEmpty() ) 208 : 0 : layer->setName( layerName ); 209 : : else 210 : : { 211 : 0 : const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString(); 212 : 0 : if ( !path.isEmpty() ) 213 : : { 214 : 0 : const QFileInfo fi( path ); 215 : 0 : layer->setName( fi.baseName() ); 216 : 0 : } 217 : 0 : else if ( !name.isEmpty() ) 218 : : { 219 : : // fallback to parameter's name -- shouldn't happen! 220 : 0 : layer->setName( name ); 221 : 0 : } 222 : 0 : } 223 : 0 : } 224 : : else 225 : : { 226 : 0 : layer->setName( name ); 227 : : } 228 : 0 : }