bool QgsWFSProvider::describeFeatureType( QString& geometryAttribute, QgsFields& fields, QGis::WkbType& geomType ) { fields.clear(); QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI.uri() ); if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion, mShared->mURI.typeName() ) ) { QgsMessageLog::logMessage( tr( "DescribeFeatureType failed for url %1: %2" ). arg( dataSourceUri() ).arg( describeFeatureType.errorMessage() ), tr( "WFS" ) ); return false; } const QByteArray& response = describeFeatureType.response(); QDomDocument describeFeatureDocument; QString errorMsg; if ( !describeFeatureDocument.setContent( response, true, &errorMsg ) ) { QgsDebugMsg( response ); QgsMessageLog::logMessage( tr( "DescribeFeatureType failed for url %1: %2" ). arg( dataSourceUri() ).arg( errorMsg ), tr( "WFS" ) ); return false; } if ( readAttributesFromSchema( describeFeatureDocument, geometryAttribute, fields, geomType ) != 0 ) { QgsMessageLog::logMessage( tr( "DescribeFeatureType failed for url %1: %2" ). arg( dataSourceUri() ).arg( tr( "failed retrieving attributes from schema" ) ), tr( "WFS" ) ); return false; } return true; }
QgsRasterInterface *QgsAmsProvider::clone() const { QgsDataProvider::ProviderOptions options; QgsAmsProvider *provider = new QgsAmsProvider( dataSourceUri(), options ); provider->copyBaseSettings( *this ); return provider; }
QgsAmsProvider::QgsAmsProvider( const QString &uri, const ProviderOptions &options ) : QgsRasterDataProvider( uri, options ) { mLegendFetcher = new QgsAmsLegendFetcher( this ); QgsDataSourceUri dataSource( dataSourceUri() ); const QString authcfg = dataSource.authConfigId(); mServiceInfo = QgsArcGisRestUtils::getServiceInfo( dataSource.param( QStringLiteral( "url" ) ), authcfg, mErrorTitle, mError ); mLayerInfo = QgsArcGisRestUtils::getLayerInfo( dataSource.param( QStringLiteral( "url" ) ) + "/" + dataSource.param( QStringLiteral( "layer" ) ), authcfg, mErrorTitle, mError ); const QVariantMap extentData = mLayerInfo.value( QStringLiteral( "extent" ) ).toMap(); mExtent.setXMinimum( extentData[QStringLiteral( "xmin" )].toDouble() ); mExtent.setYMinimum( extentData[QStringLiteral( "ymin" )].toDouble() ); mExtent.setXMaximum( extentData[QStringLiteral( "xmax" )].toDouble() ); mExtent.setYMaximum( extentData[QStringLiteral( "ymax" )].toDouble() ); mCrs = QgsArcGisRestUtils::parseSpatialReference( extentData[QStringLiteral( "spatialReference" )].toMap() ); if ( !mCrs.isValid() ) { appendError( QgsErrorMessage( tr( "Could not parse spatial reference" ), QStringLiteral( "AMSProvider" ) ) ); return; } const QVariantList subLayersList = mLayerInfo.value( QStringLiteral( "subLayers" ) ).toList(); mSubLayers.reserve( subLayersList.size() ); for ( const QVariant &sublayer : subLayersList ) { mSubLayers.append( sublayer.toMap()[QStringLiteral( "id" )].toString() ); mSubLayerVisibilities.append( true ); } mTimestamp = QDateTime::currentDateTime(); mValid = true; }
bool QgsDb2Provider::setSubsetString( const QString& theSQL, bool ) { QString prevWhere = mSqlWhereClause; QgsDebugMsg( theSQL ); mSqlWhereClause = theSQL.trimmed(); QString sql = QString( "SELECT COUNT(*) FROM " ); sql += QString( "%1.%2" ).arg( mSchemaName, mTableName ); if ( !mSqlWhereClause.isEmpty() ) { sql += QString( " WHERE %1" ).arg( mSqlWhereClause ); } if ( !openDatabase( mDatabase ) ) { return false; } QSqlQuery query = QSqlQuery( mDatabase ); query.setForwardOnly( true ); QgsDebugMsg( sql ); if ( !query.exec( sql ) ) { pushError( query.lastError().text() ); mSqlWhereClause = prevWhere; QgsDebugMsg( query.lastError().text() ); return false; } if ( query.isActive() && query.next() ) { mNumberFeatures = query.value( 0 ).toInt(); QgsDebugMsg( QString( "count: %1" ).arg( mNumberFeatures ) ); } else { pushError( query.lastError().text() ); mSqlWhereClause = prevWhere; QgsDebugMsg( query.lastError().text() ); return false; } QgsDataSourceUri anUri = QgsDataSourceUri( dataSourceUri() ); anUri.setSql( mSqlWhereClause ); setDataSourceUri( anUri.uri() ); mExtent.setMinimal(); emit dataChanged(); return true; }
bool QgsWFSProvider::getCapabilities() { mCapabilities = 0; QgsWFSCapabilities getCapabilities( mShared->mURI.uri() ); if ( !getCapabilities.requestCapabilities( true ) ) { QgsMessageLog::logMessage( tr( "GetCapabilities failed for url %1: %2" ). arg( dataSourceUri() ).arg( getCapabilities.errorMessage() ), tr( "WFS" ) ); return false; } const QgsWFSCapabilities::Capabilities caps = getCapabilities.capabilities(); mShared->mWFSVersion = caps.version; if ( mShared->mURI.maxNumFeatures() > 0 ) mShared->mMaxFeatures = mShared->mURI.maxNumFeatures(); else mShared->mMaxFeatures = caps.maxFeatures; mShared->mMaxFeaturesServer = caps.maxFeatures; mShared->mSupportsHits = caps.supportsHits; mShared->mSupportsPaging = caps.supportsPaging; //find the <FeatureType> for this layer QString thisLayerName = mShared->mURI.typeName(); for ( int i = 0; i < caps.featureTypes.size(); i++ ) { if ( thisLayerName == caps.featureTypes[i].name ) { const QgsRectangle& r = caps.featureTypes[i].bboxLongLat; if ( mShared->mSourceCRS.authid().isEmpty() && caps.featureTypes[i].crslist.size() != 0 ) { mShared->mSourceCRS.createFromOgcWmsCrs( caps.featureTypes[i].crslist[0] ); } if ( !r.isNull() ) { QgsCoordinateReferenceSystem src; src.createFromOgcWmsCrs( "CRS:84" ); QgsCoordinateTransform ct( src, mShared->mSourceCRS ); QgsDebugMsg( "latlon ext:" + r.toString() ); QgsDebugMsg( "src:" + src.authid() ); QgsDebugMsg( "dst:" + mShared->mSourceCRS.authid() ); mExtent = ct.transformBoundingBox( r, QgsCoordinateTransform::ForwardTransform ); QgsDebugMsg( "layer ext:" + mExtent.toString() ); } if ( caps.featureTypes[i].insertCap ) { mCapabilities |= QgsVectorDataProvider::AddFeatures; } if ( caps.featureTypes[i].updateCap ) { mCapabilities |= QgsVectorDataProvider::ChangeAttributeValues; mCapabilities |= QgsVectorDataProvider::ChangeGeometries; } if ( caps.featureTypes[i].deleteCap ) { mCapabilities |= QgsVectorDataProvider::DeleteFeatures; } return true; } } QgsMessageLog::logMessage( tr( "Could not find typename %1 in capabilites for url %2" ). arg( thisLayerName ).arg( dataSourceUri() ), tr( "WFS" ) ); return false; }
QgsRasterInterface *QgsGrassRasterProvider::clone() const { QgsGrassRasterProvider *provider = new QgsGrassRasterProvider( dataSourceUri() ); provider->copyBaseSettings( *this ); return provider; }
QgsRasterInterface * QgsGrassRasterProvider::clone() const { QgsGrassRasterProvider * provider = new QgsGrassRasterProvider( dataSourceUri() ); return provider; }
QgsDelimitedTextProvider::QgsDelimitedTextProvider( QString uri ) : QgsVectorDataProvider( uri ) , mDelimiter( "," ) , mDelimiterType( "plain" ) , mFieldCount( 0 ) , mXFieldIndex( -1 ) , mYFieldIndex( -1 ) , mWktFieldIndex( -1 ) , mWktHasZM( false ) , mWktZMRegexp( "\\s+(?:z|m|zm)(?=\\s*\\()", Qt::CaseInsensitive ) , mWktCrdRegexp( "(\\-?\\d+(?:\\.\\d*)?\\s+\\-?\\d+(?:\\.\\d*)?)\\s[\\s\\d\\.\\-]+" ) , mFile( 0 ) , mStream( 0 ) , mSkipLines( 0 ) , mFirstDataLine( 0 ) , mShowInvalidLines( false ) , mCrs() , mWkbType( QGis::WKBUnknown ) { QUrl url = QUrl::fromEncoded( uri.toAscii() ); // Extract the provider definition from the url mFileName = url.toLocalFile(); QString wktField; QString xField; QString yField; if ( url.hasQueryItem( "delimiter" ) ) mDelimiter = url.queryItemValue( "delimiter" ); if ( url.hasQueryItem( "delimiterType" ) ) mDelimiterType = url.queryItemValue( "delimiterType" ); if ( url.hasQueryItem( "wktField" ) ) wktField = url.queryItemValue( "wktField" ); if ( url.hasQueryItem( "xField" ) ) xField = url.queryItemValue( "xField" ); if ( url.hasQueryItem( "yField" ) ) yField = url.queryItemValue( "yField" ); if ( url.hasQueryItem( "skipLines" ) ) mSkipLines = url.queryItemValue( "skipLines" ).toInt(); if ( url.hasQueryItem( "crs" ) ) mCrs.createFromString( url.queryItemValue( "crs" ) ); if ( url.hasQueryItem( "decimalPoint" ) ) mDecimalPoint = url.queryItemValue( "decimalPoint" ); QgsDebugMsg( "Data source uri is " + uri ); QgsDebugMsg( "Delimited text file is: " + mFileName ); QgsDebugMsg( "Delimiter is: " + mDelimiter ); QgsDebugMsg( "Delimiter type is: " + mDelimiterType ); QgsDebugMsg( "wktField is: " + wktField ); QgsDebugMsg( "xField is: " + xField ); QgsDebugMsg( "yField is: " + yField ); QgsDebugMsg( "skipLines is: " + QString::number( mSkipLines ) ); // if delimiter contains some special characters, convert them if ( mDelimiterType != "regexp" ) mDelimiter.replace( "\\t", "\t" ); // replace "\t" with a real tabulator // Set the selection rectangle to null mSelectionRectangle = QgsRectangle(); // assume the layer is invalid until proven otherwise mValid = false; if ( mFileName.isEmpty() || mDelimiter.isEmpty() ) { // uri is invalid so the layer must be too... QgsDebugMsg( "Data source is invalid" ); return; } // check to see that the file exists and perform some sanity checks if ( !QFile::exists( mFileName ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " doesn't exist" ); return; } // Open the file and get number of rows, etc. We assume that the // file has a header row and process accordingly. Caller should make // sure that the delimited file is properly formed. mFile = new QFile( mFileName ); if ( !mFile->open( QIODevice::ReadOnly ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " could not be opened" ); delete mFile; mFile = 0; return; } // now we have the file opened and ready for parsing // set the initial extent mExtent = QgsRectangle(); QMap<int, bool> couldBeInt; QMap<int, bool> couldBeDouble; mStream = new QTextStream( mFile ); QString line; mNumberFeatures = 0; int lineNumber = 0; bool hasFields = false; while ( !mStream->atEnd() ) { lineNumber++; line = readLine( mStream ); // line of text excluding '\n', default local 8 bit encoding. if ( lineNumber < mSkipLines + 1 ) continue; if ( line.isEmpty() ) continue; if ( !hasFields ) { // Get the fields from the header row and store them in the // fields vector QStringList fieldList = splitLine( line ); mFieldCount = fieldList.count(); // We don't know anything about a text based field other // than its name. All fields are assumed to be text int fieldPos = 0; for ( int column = 0; column < mFieldCount; column++ ) { QString field = fieldList[column]; if (( field.left( 1 ) == "'" || field.left( 1 ) == "\"" ) && field.left( 1 ) == field.right( 1 ) ) // eat quotes field = field.mid( 1, field.length() - 2 ); if ( field.length() == 0 ) // skip empty field names continue; // check to see if this field matches either the x or y field if ( !wktField.isEmpty() && wktField == field ) { QgsDebugMsg( "Found wkt field: " + ( field ) ); mWktFieldIndex = column; } else if ( !xField.isEmpty() && xField == field ) { QgsDebugMsg( "Found x field: " + ( field ) ); mXFieldIndex = column; } else if ( !yField.isEmpty() && yField == field ) { QgsDebugMsg( "Found y field: " + ( field ) ); mYFieldIndex = column; } // WKT geometry field won't be displayed in attribute tables if ( column == mWktFieldIndex ) continue; QgsDebugMsg( "Adding field: " + ( field ) ); // assume that the field could be integer or double // for now, let's set field type as text attributeColumns.append( column ); attributeFields[fieldPos] = QgsField( field, QVariant::String, "Text" ); couldBeInt.insert( fieldPos, true ); couldBeDouble.insert( fieldPos, true ); fieldPos++; } if ( mWktFieldIndex >= 0 ) { mXFieldIndex = -1; mYFieldIndex = -1; } QgsDebugMsg( "wktfield index: " + QString::number( mWktFieldIndex ) ); QgsDebugMsg( "xfield index: " + QString::number( mXFieldIndex ) ); QgsDebugMsg( "yfield index: " + QString::number( mYFieldIndex ) ); QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) ); hasFields = true; } else // hasFields == true - field names already read { if ( mFirstDataLine == 0 ) mFirstDataLine = lineNumber; // split the line on the delimiter QStringList parts = splitLine( line ); // Ensure that the input has at least the required number of fields (mainly to tolerate // missed blank strings at end of row) while ( parts.size() < mFieldCount ) parts.append( QString::null ); if ( mWktFieldIndex >= 0 ) { // Get the wkt - confirm it is valid, get the type, and // if compatible with the rest of file, add to the extents QString sWkt = parts[mWktFieldIndex]; QgsGeometry *geom = 0; try { if ( !mWktHasZM && sWkt.indexOf( mWktZMRegexp ) >= 0 ) mWktHasZM = true; if ( mWktHasZM ) { sWkt.remove( mWktZMRegexp ).replace( mWktCrdRegexp, "\\1" ); } geom = QgsGeometry::fromWkt( sWkt ); } catch ( ... ) { mInvalidLines << line; geom = 0; } if ( geom ) { QGis::WkbType type = geom->wkbType(); if ( type != QGis::WKBNoGeometry ) { if ( mNumberFeatures == 0 ) { mNumberFeatures++; mWkbType = type; mExtent = geom->boundingBox(); } else if ( type == mWkbType ) { mNumberFeatures++; QgsRectangle bbox( geom->boundingBox() ); mExtent.combineExtentWith( &bbox ); } } delete geom; } } else if ( mWktFieldIndex == -1 && mXFieldIndex >= 0 && mYFieldIndex >= 0 ) { // Get the x and y values, first checking to make sure they // aren't null. QString sX = parts[mXFieldIndex]; QString sY = parts[mYFieldIndex]; if ( !mDecimalPoint.isEmpty() ) { sX.replace( mDecimalPoint, "." ); sY.replace( mDecimalPoint, "." ); } bool xOk = false; bool yOk = false; double x = sX.toDouble( &xOk ); double y = sY.toDouble( &yOk ); if ( xOk && yOk ) { if ( mNumberFeatures > 0 ) { mExtent.combineExtentWith( x, y ); } else { // Extent for the first point is just the first point mExtent.set( x, y, x, y ); mWkbType = QGis::WKBPoint; } mNumberFeatures++; } else { mInvalidLines << line; } } else { mWkbType = QGis::WKBNoGeometry; mNumberFeatures++; } for ( int i = 0; i < attributeFields.size(); i++ ) { QString &value = parts[attributeColumns[i]]; if ( value.isEmpty() ) continue; // try to convert attribute values to integer and double if ( couldBeInt[i] ) { value.toInt( &couldBeInt[i] ); } if ( couldBeDouble[i] ) { value.toDouble( &couldBeDouble[i] ); } } } } QgsDebugMsg( "geometry type is: " + QString::number( mWkbType ) ); QgsDebugMsg( "feature count is: " + QString::number( mNumberFeatures ) ); // now it's time to decide the types for the fields for ( QgsFieldMap::iterator it = attributeFields.begin(); it != attributeFields.end(); ++it ) { if ( couldBeInt[it.key()] ) { it->setType( QVariant::Int ); it->setTypeName( "integer" ); } else if ( couldBeDouble[it.key()] ) { it->setType( QVariant::Double ); it->setTypeName( "double" ); } } mValid = mWkbType != QGis::WKBUnknown; }
QgsRasterIdentifyResult QgsAmsProvider::identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &extent, int width, int height, int dpi ) { // http://resources.arcgis.com/en/help/rest/apiref/identify.html QgsDataSourceUri dataSource( dataSourceUri() ); QUrl queryUrl( dataSource.param( QStringLiteral( "url" ) ) + "/identify" ); queryUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "json" ) ); queryUrl.addQueryItem( QStringLiteral( "geometryType" ), QStringLiteral( "esriGeometryPoint" ) ); queryUrl.addQueryItem( QStringLiteral( "geometry" ), QStringLiteral( "{x: %1, y: %2}" ).arg( point.x(), 0, 'f' ).arg( point.y(), 0, 'f' ) ); // queryUrl.addQueryItem( "sr", mCrs.postgisSrid() ); queryUrl.addQueryItem( QStringLiteral( "layers" ), QStringLiteral( "all:%1" ).arg( dataSource.param( QStringLiteral( "layer" ) ) ) ); queryUrl.addQueryItem( QStringLiteral( "imageDisplay" ), QStringLiteral( "%1,%2,%3" ).arg( width ).arg( height ).arg( dpi ) ); queryUrl.addQueryItem( QStringLiteral( "mapExtent" ), QStringLiteral( "%1,%2,%3,%4" ).arg( extent.xMinimum(), 0, 'f' ).arg( extent.yMinimum(), 0, 'f' ).arg( extent.xMaximum(), 0, 'f' ).arg( extent.yMaximum(), 0, 'f' ) ); queryUrl.addQueryItem( QStringLiteral( "tolerance" ), QStringLiteral( "10" ) ); const QString authcfg = dataSource.param( QStringLiteral( "authcfg" ) ); const QVariantList queryResults = QgsArcGisRestUtils::queryServiceJSON( queryUrl, authcfg, mErrorTitle, mError ).value( QStringLiteral( "results" ) ).toList(); QMap<int, QVariant> entries; if ( format == QgsRaster::IdentifyFormatText ) { for ( const QVariant &result : queryResults ) { const QVariantMap resultMap = result.toMap(); QVariantMap attributesMap = resultMap[QStringLiteral( "attributes" )].toMap(); QString valueStr; for ( auto it = attributesMap.constBegin(); it != attributesMap.constEnd(); ++it ) { valueStr += QStringLiteral( "%1 = %2\n" ).arg( it.key(), it.value().toString() ); } entries.insert( entries.size(), valueStr ); } } else if ( format == QgsRaster::IdentifyFormatFeature ) { for ( const QVariant &result : queryResults ) { const QVariantMap resultMap = result.toMap(); QgsFields fields; const QVariantMap attributesMap = resultMap[QStringLiteral( "attributes" )].toMap(); QgsAttributes featureAttributes; for ( auto it = attributesMap.constBegin(); it != attributesMap.constEnd(); ++it ) { fields.append( QgsField( it.key(), QVariant::String, QStringLiteral( "string" ) ) ); featureAttributes.append( it.value().toString() ); } QgsCoordinateReferenceSystem crs; std::unique_ptr< QgsAbstractGeometry > geometry = QgsArcGisRestUtils::parseEsriGeoJSON( resultMap[QStringLiteral( "geometry" )].toMap(), resultMap[QStringLiteral( "geometryType" )].toString(), false, false, &crs ); QgsFeature feature( fields ); feature.setGeometry( QgsGeometry( std::move( geometry ) ) ); feature.setAttributes( featureAttributes ); feature.setValid( true ); QgsFeatureStore store( fields, crs ); QMap<QString, QVariant> params; params[QStringLiteral( "sublayer" )] = resultMap[QStringLiteral( "layerName" )].toString(); params[QStringLiteral( "featureType" )] = attributesMap[resultMap[QStringLiteral( "displayFieldName" )].toString()].toString(); store.setParams( params ); store.addFeature( feature ); entries.insert( entries.size(), qVariantFromValue( QList<QgsFeatureStore>() << store ) ); } } return QgsRasterIdentifyResult( format, entries ); }
void QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int pixelHeight ) { if ( !mCachedImage.isNull() && mCachedImageExtent == viewExtent ) { return; } QgsDataSourceUri dataSource( dataSourceUri() ); const QString authcfg = dataSource.param( QStringLiteral( "authcfg" ) ); // Use of tiles currently only implemented if service CRS is meter based if ( mServiceInfo[QStringLiteral( "singleFusedMapCache" )].toBool() && mCrs.mapUnits() == QgsUnitTypes::DistanceMeters ) { // Compute ideal resolution // - Measure distance in meters along lower and upper edge of bounding box // - Target resolution is the coarser resolution (resolution = distMeters / pixelWidth) double width = viewExtent.xMaximum() - viewExtent.xMinimum(); double targetRes = width / ( pixelWidth ); // Tiles available, assemble image from tiles QVariantMap tileInfo = mServiceInfo[QStringLiteral( "tileInfo" )].toMap(); int tileWidth = tileInfo[QStringLiteral( "cols" )].toInt(); int tileHeight = tileInfo[QStringLiteral( "rows" )].toInt(); QVariantMap origin = tileInfo[QStringLiteral( "origin" )].toMap(); double ox = origin[QStringLiteral( "x" )].toDouble(); double oy = origin[QStringLiteral( "y" )].toDouble(); // Search matching resolution (tile resolution <= targetRes) const QList<QVariant> lodEntries = tileInfo[QStringLiteral( "lods" )].toList(); if ( lodEntries.isEmpty() ) { mCachedImage = QImage(); mCachedImage.fill( Qt::transparent ); return; } int level = 0; double resolution = lodEntries.front().toMap()[QStringLiteral( "resolution" )].toDouble(); for ( const QVariant &lodEntry : lodEntries ) { QVariantMap lodEntryMap = lodEntry.toMap(); level = lodEntryMap[QStringLiteral( "level" )].toInt(); resolution = lodEntryMap[QStringLiteral( "resolution" )].toDouble(); if ( lodEntryMap[QStringLiteral( "resolution" )].toDouble() <= 1.5 * targetRes ) { break; } } // Get necessary tiles to fill extent // tile_x = ox + i * (resolution * tileWidth) // tile_y = oy - j * (resolution * tileHeight) int ixStart = std::floor( ( viewExtent.xMinimum() - ox ) / ( tileWidth * resolution ) ); int iyStart = std::floor( ( oy - viewExtent.yMaximum() ) / ( tileHeight * resolution ) ); int ixEnd = std::ceil( ( viewExtent.xMaximum() - ox ) / ( tileWidth * resolution ) ); int iyEnd = std::ceil( ( oy - viewExtent.yMinimum() ) / ( tileHeight * resolution ) ); double imX = ( viewExtent.xMinimum() - ox ) / resolution; double imY = ( oy - viewExtent.yMaximum() ) / resolution; // Query tiles int ixCount = ( ixEnd - ixStart + 1 ); QVector<QByteArray> results( ixCount * ( iyEnd - iyStart + 1 ) ); QVector<QUrl> queries( ixCount * ( iyEnd - iyStart + 1 ) ); for ( int iy = iyStart; iy <= iyEnd; ++iy ) { for ( int ix = ixStart; ix <= ixEnd; ++ix ) { queries[( iy - iyStart ) * ixCount + ( ix - ixStart )] = QUrl( dataSource.param( QStringLiteral( "url" ) ) + QStringLiteral( "/tile/%1/%2/%3" ).arg( level ).arg( iy ).arg( ix ) ); } } QgsArcGisAsyncParallelQuery query; QEventLoop evLoop; connect( &query, &QgsArcGisAsyncParallelQuery::finished, &evLoop, &QEventLoop::quit ); query.start( queries, &results, true ); evLoop.exec( QEventLoop::ExcludeUserInputEvents ); // Fill image mCachedImage = QImage( pixelWidth, pixelHeight, QImage::Format_ARGB32 ); mCachedImage.fill( Qt::transparent ); QPainter painter( &mCachedImage ); painter.setRenderHint( QPainter::SmoothPixmapTransform, true ); double resScale = resolution / targetRes; painter.scale( resScale, resScale ); for ( int iy = iyStart; iy <= iyEnd; ++iy ) { for ( int ix = ixStart; ix <= ixEnd; ++ix ) { QImage image = QImage::fromData( results[( iy - iyStart ) * ixCount + ( ix - ixStart )], tileInfo[QStringLiteral( "format" )].toByteArray() ); painter.drawImage( QPointF( ix * tileWidth - imX, iy * tileHeight - imY ), image ); } } } else { QUrl requestUrl( dataSource.param( QStringLiteral( "url" ) ) + "/export" ); requestUrl.addQueryItem( QStringLiteral( "bbox" ), QStringLiteral( "%1,%2,%3,%4" ).arg( viewExtent.xMinimum(), 0, 'f', -1 ).arg( viewExtent.yMinimum(), 0, 'f', -1 ).arg( viewExtent.xMaximum(), 0, 'f', -1 ).arg( viewExtent.yMaximum(), 0, 'f', -1 ) ); requestUrl.addQueryItem( QStringLiteral( "size" ), QStringLiteral( "%1,%2" ).arg( pixelWidth ).arg( pixelHeight ) ); requestUrl.addQueryItem( QStringLiteral( "format" ), dataSource.param( QStringLiteral( "format" ) ) ); requestUrl.addQueryItem( QStringLiteral( "layers" ), QStringLiteral( "show:%1" ).arg( dataSource.param( QStringLiteral( "layer" ) ) ) ); requestUrl.addQueryItem( QStringLiteral( "transparent" ), QStringLiteral( "true" ) ); requestUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "image" ) ); QByteArray reply = QgsArcGisRestUtils::queryService( requestUrl, authcfg, mErrorTitle, mError ); mCachedImage = QImage::fromData( reply, dataSource.param( QStringLiteral( "format" ) ).toLatin1() ); if ( mCachedImage.format() != QImage::Format_ARGB32 ) { mCachedImage = mCachedImage.convertToFormat( QImage::Format_ARGB32 ); } } }
QgsDelimitedTextProvider::QgsDelimitedTextProvider( QString uri ) : QgsVectorDataProvider( uri ), mXFieldIndex( -1 ), mYFieldIndex( -1 ), mShowInvalidLines( true ) { // Get the file name and mDelimiter out of the uri mFileName = uri.left( uri.indexOf( "?" ) ); // split the string up on & to get the individual parameters QStringList parameters = uri.mid( uri.indexOf( "?" ) ).split( "&", QString::SkipEmptyParts ); QgsDebugMsg( "Parameter count after split on &" + QString::number( parameters.size() ) ); // get the individual parameters and assign values QStringList temp = parameters.filter( "delimiter=" ); mDelimiter = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : ""; temp = parameters.filter( "delimiterType=" ); mDelimiterType = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : ""; temp = parameters.filter( "xField=" ); QString xField = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : ""; temp = parameters.filter( "yField=" ); QString yField = temp.size() ? temp[0].mid( temp[0].indexOf( "=" ) + 1 ) : ""; // Decode the parts of the uri. Good if someone entered '=' as a delimiter, for instance. mFileName = QUrl::fromPercentEncoding( mFileName.toUtf8() ); mDelimiter = QUrl::fromPercentEncoding( mDelimiter.toUtf8() ); mDelimiterType = QUrl::fromPercentEncoding( mDelimiterType.toUtf8() ); xField = QUrl::fromPercentEncoding( xField.toUtf8() ); yField = QUrl::fromPercentEncoding( yField.toUtf8() ); QgsDebugMsg( "Data source uri is " + uri ); QgsDebugMsg( "Delimited text file is: " + mFileName ); QgsDebugMsg( "Delimiter is: " + mDelimiter ); QgsDebugMsg( "Delimiter type is: " + mDelimiterType ); QgsDebugMsg( "xField is: " + xField ); QgsDebugMsg( "yField is: " + yField ); // if delimiter contains some special characters, convert them if ( mDelimiterType == "regexp" ) mDelimiterRegexp = QRegExp( mDelimiter ); else mDelimiter.replace( "\\t", "\t" ); // replace "\t" with a real tabulator // Set the selection rectangle to null mSelectionRectangle = QgsRectangle(); // assume the layer is invalid until proven otherwise mValid = false; if ( mFileName.isEmpty() || mDelimiter.isEmpty() || xField.isEmpty() || yField.isEmpty() ) { // uri is invalid so the layer must be too... QString( "Data source is invalid" ); return; } // check to see that the file exists and perform some sanity checks if ( !QFile::exists( mFileName ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " doesn't exist" ); return; } // Open the file and get number of rows, etc. We assume that the // file has a header row and process accordingly. Caller should make // sure the the delimited file is properly formed. mFile = new QFile( mFileName ); if ( !mFile->open( QIODevice::ReadOnly ) ) { QgsDebugMsg( "Data source " + dataSourceUri() + " could not be opened" ); delete mFile; return; } // now we have the file opened and ready for parsing // set the initial extent mExtent = QgsRectangle(); QMap<int, bool> couldBeInt; QMap<int, bool> couldBeDouble; mStream = new QTextStream( mFile ); QString line; mNumberFeatures = 0; int lineNumber = 0; bool firstPoint = true; bool hasFields = false; while ( !mStream->atEnd() ) { lineNumber++; line = mStream->readLine(); // line of text excluding '\n', default local 8 bit encoding. if ( !hasFields ) { // Get the fields from the header row and store them in the // fields vector QgsDebugMsg( "Attempting to split the input line: " + line + " using delimiter " + mDelimiter ); QStringList fieldList; if ( mDelimiterType == "regexp" ) fieldList = line.split( mDelimiterRegexp ); else fieldList = line.split( mDelimiter ); QgsDebugMsg( "Split line into " + QString::number( fieldList.size() ) + " parts" ); // We don't know anything about a text based field other // than its name. All fields are assumed to be text int fieldPos = 0; for ( QStringList::Iterator it = fieldList.begin(); it != fieldList.end(); ++it ) { QString field = *it; if ( field.length() > 0 ) { // for now, let's set field type as text attributeFields[fieldPos] = QgsField( *it, QVariant::String, "Text" ); // check to see if this field matches either the x or y field if ( xField == *it ) { QgsDebugMsg( "Found x field: " + ( *it ) ); mXFieldIndex = fieldPos; } else if ( yField == *it ) { QgsDebugMsg( "Found y field: " + ( *it ) ); mYFieldIndex = fieldPos; } QgsDebugMsg( "Adding field: " + ( *it ) ); // assume that the field could be integer or double couldBeInt.insert( fieldPos, true ); couldBeDouble.insert( fieldPos, true ); fieldPos++; } } QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) ); hasFields = true; } else if ( mXFieldIndex != -1 && mYFieldIndex != -1 ) { mNumberFeatures++; // split the line on the delimiter QStringList parts; if ( mDelimiterType == "regexp" ) parts = line.split( mDelimiterRegexp ); else parts = line.split( mDelimiter ); // Skip malformed lines silently. Report line number with nextFeature() if ( attributeFields.size() != parts.size() ) { continue; } // Get the x and y values, first checking to make sure they // aren't null. QString sX = parts[mXFieldIndex]; QString sY = parts[mYFieldIndex]; bool xOk = true; bool yOk = true; double x = sX.toDouble( &xOk ); double y = sY.toDouble( &yOk ); if ( xOk && yOk ) { if ( !firstPoint ) { mExtent.combineExtentWith( x, y ); } else { // Extent for the first point is just the first point mExtent.set( x, y, x, y ); firstPoint = false; } } int i = 0; for ( QStringList::iterator it = parts.begin(); it != parts.end(); ++it, ++i ) { // try to convert attribute values to integer and double if ( couldBeInt[i] ) { it->toInt( &couldBeInt[i] ); } if ( couldBeDouble[i] ) { it->toDouble( &couldBeDouble[i] ); } } } } // now it's time to decide the types for the fields for ( QgsFieldMap::iterator it = attributeFields.begin(); it != attributeFields.end(); ++it ) { if ( couldBeInt[it.key()] ) { it->setType( QVariant::Int ); it->setTypeName( "integer" ); } else if ( couldBeDouble[it.key()] ) { it->setType( QVariant::Double ); it->setTypeName( "double" ); } } if ( mXFieldIndex != -1 && mYFieldIndex != -1 ) { QgsDebugMsg( "Data store is valid" ); QgsDebugMsg( "Number of features " + QString::number( mNumberFeatures ) ); QgsDebugMsg( "Extents " + mExtent.toString() ); mValid = true; } else { QgsDebugMsg( "Data store is invalid. Specified x,y fields do not match those in the database" ); } QgsDebugMsg( "Done checking validity" ); }