25 #include <QNetworkRequest>
26 #include <QJsonDocument>
27 #include <QJsonObject>
29 QReadWriteLock QgsGoogleMapsGeocoder::sMutex;
38 , mRegion( regionBias )
39 , mEndpoint( QStringLiteral( "https:
52 fields.
append(
QgsField( QStringLiteral(
"location_type" ), QVariant::String ) );
53 fields.
append(
QgsField( QStringLiteral(
"formatted_address" ), QVariant::String ) );
54 fields.
append(
QgsField( QStringLiteral(
"place_id" ), QVariant::String ) );
57 fields.
append(
QgsField( QStringLiteral(
"street_number" ), QVariant::String ) );
58 fields.
append(
QgsField( QStringLiteral(
"route" ), QVariant::String ) );
59 fields.
append(
QgsField( QStringLiteral(
"locality" ), QVariant::String ) );
60 fields.
append(
QgsField( QStringLiteral(
"administrative_area_level_2" ), QVariant::String ) );
61 fields.
append(
QgsField( QStringLiteral(
"administrative_area_level_1" ), QVariant::String ) );
62 fields.
append(
QgsField( QStringLiteral(
"country" ), QVariant::String ) );
63 fields.
append(
QgsField( QStringLiteral(
"postal_code" ), QVariant::String ) );
86 QgsDebugMsg(
"Could not transform geocode bounds to WGS84" );
93 const auto it = sCachedResults()->constFind( url );
94 if ( it != sCachedResults()->constEnd() )
100 QNetworkRequest request( url );
112 const QJsonDocument doc = QJsonDocument::fromJson( newReq.
reply().
content(), &err );
117 const QVariantMap res = doc.object().toVariantMap();
118 const QString status = res.value( QStringLiteral(
"status" ) ).toString();
119 if ( status.isEmpty() || !res.contains( QStringLiteral(
"results" ) ) )
121 return QList<QgsGeocoderResult>();
124 if ( res.contains( QLatin1String(
"error_message" ) ) )
129 if ( status == QLatin1String(
"REQUEST_DENIED" ) || status == QLatin1String(
"OVER_QUERY_LIMIT" ) )
133 if ( status != QLatin1String(
"OK" ) && status != QLatin1String(
"ZERO_RESULTS" ) )
141 const QVariantList results = res.value( QStringLiteral(
"results" ) ).toList();
142 if ( results.empty() )
144 sCachedResults()->insert( url, QList<QgsGeocoderResult>() );
145 return QList<QgsGeocoderResult>();
148 QList< QgsGeocoderResult > matches;
149 matches.reserve( results.size( ) );
150 for (
const QVariant &result : results )
154 sCachedResults()->insert( url, matches );
161 QUrl res( mEndpoint );
165 query.addQueryItem( QStringLiteral(
"bounds" ), QStringLiteral(
"%1,%2|%3,%4" ).arg( bounds.
yMinimum() )
170 if ( !mRegion.isEmpty() )
172 query.addQueryItem( QStringLiteral(
"region" ), mRegion.toLower() );
174 query.addQueryItem( QStringLiteral(
"sensor" ), QStringLiteral(
"false" ) );
175 query.addQueryItem( QStringLiteral(
"address" ), address );
176 query.addQueryItem( QStringLiteral(
"key" ), mApiKey );
177 res.setQuery( query );
180 if ( res.toString().contains( QLatin1String(
"fake_qgis_http_endpoint" ) ) )
183 QString modifiedUrlString = res.toString();
185 modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() );
186 modifiedUrlString.replace( QLatin1String(
"fake_qgis_http_endpoint/" ), QLatin1String(
"fake_qgis_http_endpoint_" ) );
187 QgsDebugMsg( QStringLiteral(
"Get %1" ).arg( modifiedUrlString ) );
188 modifiedUrlString = modifiedUrlString.mid( QStringLiteral(
"http://" ).size() );
189 QString args = modifiedUrlString.mid( modifiedUrlString.indexOf(
'?' ) );
190 if ( modifiedUrlString.size() > 150 )
192 args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
196 args.replace( QLatin1String(
"?" ), QLatin1String(
"_" ) );
197 args.replace( QLatin1String(
"&" ), QLatin1String(
"_" ) );
198 args.replace( QLatin1String(
"<" ), QLatin1String(
"_" ) );
199 args.replace( QLatin1String(
">" ), QLatin1String(
"_" ) );
200 args.replace( QLatin1String(
"'" ), QLatin1String(
"_" ) );
201 args.replace( QLatin1String(
"\"" ), QLatin1String(
"_" ) );
202 args.replace( QLatin1String(
" " ), QLatin1String(
"_" ) );
203 args.replace( QLatin1String(
":" ), QLatin1String(
"_" ) );
204 args.replace( QLatin1String(
"/" ), QLatin1String(
"_" ) );
205 args.replace( QLatin1String(
"\n" ), QLatin1String(
"_" ) );
210 if ( modifiedUrlString[1] ==
'/' )
212 modifiedUrlString = modifiedUrlString[0] +
":/" + modifiedUrlString.mid( 2 );
215 modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf(
'?' ) ) + args;
216 QgsDebugMsg( QStringLiteral(
"Get %1 (after laundering)" ).arg( modifiedUrlString ) );
217 res = QUrl::fromLocalFile( modifiedUrlString );
225 const QVariantMap geometry = json.value( QStringLiteral(
"geometry" ) ).toMap();
226 const QVariantMap location = geometry.value( QStringLiteral(
"location" ) ).toMap();
227 const double latitude = location.value( QStringLiteral(
"lat" ) ).toDouble();
228 const double longitude = location.value( QStringLiteral(
"lng" ) ).toDouble();
232 QgsGeocoderResult res( json.value( QStringLiteral(
"formatted_address" ) ).toString(),
236 QVariantMap attributes;
238 if ( json.contains( QStringLiteral(
"formatted_address" ) ) )
239 attributes.insert( QStringLiteral(
"formatted_address" ), json.value( QStringLiteral(
"formatted_address" ) ).toString() );
240 if ( json.contains( QStringLiteral(
"place_id" ) ) )
241 attributes.insert( QStringLiteral(
"place_id" ), json.value( QStringLiteral(
"place_id" ) ).toString() );
242 if ( geometry.contains( QStringLiteral(
"location_type" ) ) )
243 attributes.insert( QStringLiteral(
"location_type" ), geometry.value( QStringLiteral(
"location_type" ) ).toString() );
245 const QVariantList components = json.value( QStringLiteral(
"address_components" ) ).toList();
246 for (
const QVariant &component : components )
248 const QVariantMap componentMap = component.toMap();
249 const QStringList types = componentMap.value( QStringLiteral(
"types" ) ).toStringList();
251 for (
const QString &t :
253 QStringLiteral(
"street_number" ),
254 QStringLiteral(
"route" ),
255 QStringLiteral(
"locality" ),
256 QStringLiteral(
"administrative_area_level_2" ),
257 QStringLiteral(
"administrative_area_level_1" ),
258 QStringLiteral(
"country" ),
259 QStringLiteral(
"postal_code" )
262 if ( types.contains( t ) )
264 attributes.insert( t, componentMap.value( QStringLiteral(
"long_name" ) ).toString() );
265 if ( t == QLatin1String(
"administrative_area_level_1" ) )
266 res.
setGroup( componentMap.value( QStringLiteral(
"long_name" ) ).toString() );
271 if ( geometry.contains( QStringLiteral(
"viewport" ) ) )
273 const QVariantMap viewport = geometry.value( QStringLiteral(
"viewport" ) ).toMap();
274 const QVariantMap northEast = viewport.value( QStringLiteral(
"northeast" ) ).toMap();
275 const QVariantMap southWest = viewport.value( QStringLiteral(
"southwest" ) ).toMap();
277 southWest.value( QStringLiteral(
"lat" ) ).toDouble(),
278 northEast.value( QStringLiteral(
"lng" ) ).toDouble(),
279 northEast.value( QStringLiteral(
"lat" ) ).toDouble()
289 mEndpoint = endpoint;