File indexing completed on 2025-01-19 03:58:07
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2011-04-30 0007 * Description : Class for geonames.org based altitude lookup 0008 * 0009 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2010-2011 by Michael G. Hansen <mike at mghansen dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "lookupaltitudegeonames.h" 0017 0018 // Qt includes 0019 0020 0021 #include <QUrlQuery> 0022 #include <QRegularExpression> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "geoifacetypes.h" 0031 #include "networkmanager.h" 0032 0033 namespace Digikam 0034 { 0035 0036 class Q_DECL_HIDDEN MergedRequests 0037 { 0038 public: 0039 0040 QList<QPair<GeoCoordinates, QIntList> > groupedRequestIndices; 0041 0042 typedef QList<MergedRequests> List; 0043 0044 bool addRequestIfCoordinatesAreThere(const LookupAltitude::Request& request, const int requestIndex) 0045 { 0046 for (int i = 0 ; i < groupedRequestIndices.size() ; ++i) 0047 { 0048 if (groupedRequestIndices.at(i).first.sameLonLatAs(request.coordinates)) 0049 { 0050 groupedRequestIndices[i].second << requestIndex; 0051 return true; 0052 } 0053 } 0054 0055 return false; 0056 } 0057 }; 0058 0059 // ------------------------------------------------------------ 0060 0061 class Q_DECL_HIDDEN LookupAltitudeGeonames::Private 0062 { 0063 public: 0064 0065 explicit Private() 0066 : status (StatusSuccess), 0067 currentMergedRequestIndex(0), 0068 netReply (nullptr), 0069 mngr (nullptr) 0070 0071 { 0072 } 0073 0074 public: 0075 0076 Request::List requests; 0077 MergedRequests::List mergedRequests; 0078 StatusAltitude status; 0079 QString errorMessage; 0080 0081 int currentMergedRequestIndex; 0082 0083 QNetworkReply* netReply; 0084 QNetworkAccessManager* mngr; 0085 }; 0086 0087 // ------------------------------------------------------------ 0088 0089 LookupAltitudeGeonames::LookupAltitudeGeonames(QObject* const parent) 0090 : LookupAltitude(parent), 0091 d(new Private) 0092 { 0093 d->mngr = NetworkManager::instance()->getNetworkManager(this); 0094 0095 connect(d->mngr, SIGNAL(finished(QNetworkReply*)), 0096 this, SLOT(slotFinished(QNetworkReply*))); 0097 } 0098 0099 LookupAltitudeGeonames::~LookupAltitudeGeonames() 0100 { 0101 } 0102 0103 QString LookupAltitudeGeonames::backendName() const 0104 { 0105 return QLatin1String("geonames"); 0106 } 0107 0108 QString LookupAltitudeGeonames::backendHumanName() const 0109 { 0110 return i18n("geonames.org"); 0111 } 0112 0113 void LookupAltitudeGeonames::addRequests(const Request::List& requests) 0114 { 0115 d->requests << requests; 0116 } 0117 0118 LookupAltitude::Request::List LookupAltitudeGeonames::getRequests() const 0119 { 0120 return d->requests; 0121 } 0122 0123 LookupAltitude::Request LookupAltitudeGeonames::getRequest(const int index) const 0124 { 0125 return d->requests.at(index); 0126 } 0127 0128 void LookupAltitudeGeonames::startLookup() 0129 { 0130 MergedRequests currentMergedRequest; 0131 0132 for (int i = 0 ; i < d->requests.size() ; ++i) 0133 { 0134 const Request& currentRequest = d->requests.at(i); 0135 0136 // is there another request with the same coordinates? 0137 0138 bool requestAdded = currentMergedRequest.addRequestIfCoordinatesAreThere(currentRequest, i); 0139 0140 for (int j = 0 ; (!requestAdded) && j < d->mergedRequests.size() ; ++j) 0141 { 0142 requestAdded = d->mergedRequests[j].addRequestIfCoordinatesAreThere(currentRequest, i); 0143 } 0144 0145 if (!requestAdded) 0146 { 0147 currentMergedRequest.groupedRequestIndices.append(QPair<GeoCoordinates, QIntList>(currentRequest.coordinates, QIntList()<<i)); 0148 0149 if (currentMergedRequest.groupedRequestIndices.size() >= (20-1)) 0150 { 0151 d->mergedRequests << currentMergedRequest; 0152 currentMergedRequest = MergedRequests(); 0153 } 0154 } 0155 } 0156 0157 if (!currentMergedRequest.groupedRequestIndices.isEmpty()) 0158 { 0159 d->mergedRequests << currentMergedRequest; 0160 } 0161 0162 // all requests have been grouped into batches of 20, now start the first one 0163 0164 d->currentMergedRequestIndex = -1; 0165 startNextRequest(); 0166 } 0167 0168 void LookupAltitudeGeonames::startNextRequest() 0169 { 0170 ++(d->currentMergedRequestIndex); 0171 0172 if (d->currentMergedRequestIndex >= d->mergedRequests.count()) 0173 { 0174 d->status = StatusSuccess; 0175 0176 Q_EMIT signalDone(); 0177 0178 return; 0179 } 0180 0181 const MergedRequests& currentMergedRequest = d->mergedRequests.at(d->currentMergedRequestIndex); 0182 0183 QString latString; 0184 QString lonString; 0185 0186 for (int i = 0 ; i < currentMergedRequest.groupedRequestIndices.count() ; ++i) 0187 { 0188 const QPair<GeoCoordinates, QIntList>& currentPair = currentMergedRequest.groupedRequestIndices.at(i); 0189 const GeoCoordinates requestCoordinates = currentPair.first; 0190 0191 if (!latString.isEmpty()) 0192 { 0193 latString += QLatin1Char(','); 0194 lonString += QLatin1Char(','); 0195 } 0196 0197 latString += requestCoordinates.latString(); 0198 lonString += requestCoordinates.lonString(); 0199 } 0200 0201 QUrl netUrl(QLatin1String("http://api.geonames.org/srtm3")); // krazy:exclude=insecurenet 0202 0203 QUrlQuery q(netUrl); 0204 q.addQueryItem(QLatin1String("lats"), latString); 0205 q.addQueryItem(QLatin1String("lngs"), lonString); 0206 q.addQueryItem(QLatin1String("username"), QLatin1String("digikam")); 0207 netUrl.setQuery(q); 0208 0209 d->netReply = d->mngr->get(QNetworkRequest(netUrl)); 0210 } 0211 0212 void LookupAltitudeGeonames::slotFinished(QNetworkReply* reply) 0213 { 0214 if (reply != d->netReply) 0215 { 0216 return; 0217 } 0218 0219 if (reply->error() != QNetworkReply::NoError) 0220 { 0221 d->errorMessage = reply->errorString(); 0222 d->status = StatusError; 0223 0224 // after an error, we abort: 0225 0226 reply->deleteLater(); 0227 0228 Q_EMIT signalDone(); 0229 0230 return; 0231 } 0232 0233 QByteArray data = reply->readAll(); 0234 const QStringList altitudes = QString::fromLatin1(data).split(QRegularExpression(QLatin1String("\\s+"))); 0235 const MergedRequests& currentMergedRequest = d->mergedRequests.at(d->currentMergedRequestIndex); 0236 QIntList readyRequests; 0237 0238 for (int i = 0 ; i < qMin(altitudes.count(), currentMergedRequest.groupedRequestIndices.count()) ; ++i) 0239 { 0240 const QString& altitudeString = altitudes.at(i); 0241 bool haveAltitude = false; 0242 const qreal altitude = altitudeString.toFloat(&haveAltitude); 0243 0244 // -32786 means that geonames.org has no data for these coordinates 0245 0246 if (altitude == -32768) 0247 { 0248 haveAltitude = false; 0249 } 0250 0251 const QIntList& currentRequestIndexes = currentMergedRequest.groupedRequestIndices.at(i).second; 0252 0253 Q_FOREACH (const int requestIndex, currentRequestIndexes) 0254 { 0255 if (haveAltitude) 0256 { 0257 d->requests[requestIndex].coordinates.setAlt(altitude); 0258 } 0259 else 0260 { 0261 d->requests[requestIndex].coordinates.clearAlt(); 0262 } 0263 0264 // The request has been carried out. Even if no altitude was 0265 // found, we return success. 0266 0267 d->requests[requestIndex].success = true; 0268 } 0269 0270 readyRequests << currentRequestIndexes; 0271 } 0272 0273 Q_EMIT signalRequestsReady(readyRequests); 0274 0275 reply->deleteLater(); 0276 0277 startNextRequest(); 0278 } 0279 0280 LookupAltitude::StatusAltitude LookupAltitudeGeonames::getStatus() const 0281 { 0282 return d->status; 0283 } 0284 0285 QString LookupAltitudeGeonames::errorMessage() const 0286 { 0287 return d->errorMessage; 0288 } 0289 0290 void LookupAltitudeGeonames::cancel() 0291 { 0292 if (d->netReply && !d->netReply->isFinished()) 0293 { 0294 d->netReply->abort(); 0295 } 0296 0297 d->status = StatusCanceled; 0298 0299 Q_EMIT signalDone(); 0300 } 0301 0302 } // namespace Digikam 0303 0304 #include "moc_lookupaltitudegeonames.cpp"