/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "databaseoperations_p.h" #include "qlandmarkfilehandler_gpx_p.h" #include "qlandmarkfilehandler_lmx_p.h" #include "qlandmarkmanagerengine_sqlite_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QTM_USE_NAMESPACE QTM_BEGIN_NAMESPACE uint qHash(const QLandmarkId& key) { return qHash(key.localId()); } QTM_END_NAMESPACE namespace DatabaseOperationsHelpers{ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif static const double EARTH_MEAN_RADIUS = 6371.0072; QString quoteString(const QString &s) { QString q = "\""; q += s; q += "\""; return q; } bool isValidLat(double lat) { return -90.0 <= lat && lat <=90.0; } bool isValidLong(double lng) { return -180.0 <= lng && lng <= 180.0; } bool matchString(const QString &sourceString, const QString &matchString, QLandmarkFilter::MatchFlags matchFlags ) { Qt::CaseSensitivity cs; if (matchFlags & QLandmarkFilter::MatchCaseSensitive) cs = Qt::CaseSensitive; else cs = Qt::CaseInsensitive; if ((matchFlags & 3) == QLandmarkFilter::MatchEndsWith) { return sourceString.endsWith(matchString, cs); } else if ((matchFlags & 3) == QLandmarkFilter::MatchStartsWith) { return sourceString.startsWith(matchString, cs); } else if ((matchFlags & 3) == QLandmarkFilter::MatchContains) { return sourceString.contains(matchString,cs); } else if (matchFlags & QLandmarkFilter::MatchFixedString) { return sourceString.compare(matchString,cs) == 0; } else { return QVariant(sourceString) == QVariant(matchString); } } QVariant getCategoryAttribute(QLandmarkCategory *category, const QString &key) { if (key.compare("name",Qt::CaseSensitive) == 0) { return category->name(); } else if (key.compare("iconUrl",Qt::CaseSensitive) ==0) { return category->iconUrl(); } Q_ASSERT(false);//This should not be reachable return QVariant(); } void setCategoryAttribute(QLandmarkCategory *category, const QString &key, const QVariant &value) { if (key.compare("name",Qt::CaseInsensitive) == 0) { category->setName(value.toString()); return; } else if (key.compare("iconUrl",Qt::CaseInsensitive) ==0) { category->setIconUrl(QUrl(value.toUrl())); return; } Q_ASSERT(false);//This should not be reachable return; } QVariant getLandmarkAttribute(QLandmark *landmark, const QString &key) { if (key.compare("name",Qt::CaseSensitive) == 0) { return landmark->name(); } else if (key.compare("description", Qt::CaseSensitive) == 0) { return landmark->description(); } else if (key.compare("iconUrl",Qt::CaseSensitive) ==0) { return landmark->iconUrl(); } else if (key.compare("radius", Qt::CaseSensitive) == 0) { return landmark->radius(); } else if (key.compare("phoneNumber", Qt::CaseSensitive) == 0) { return landmark->phoneNumber(); } else if (key.compare("url", Qt::CaseSensitive) ==0 ) { return landmark->url(); } else if (key.compare("latitude", Qt::CaseSensitive)== 0) { return landmark->coordinate().latitude(); } else if (key.compare("longitude", Qt::CaseSensitive) ==0) { return landmark->coordinate().longitude(); } else if (key.compare("altitude", Qt::CaseSensitive) ==0) { return landmark->coordinate().altitude(); } else if (key.compare("country", Qt::CaseSensitive) ==0 ){ return landmark->address().country(); } else if (key.compare("countryCode", Qt::CaseSensitive) ==0 ){ return landmark->address().countryCode(); } else if (key.compare("state", Qt::CaseSensitive) ==0 ){ return landmark->address().state(); } else if (key.compare("county", Qt::CaseSensitive) ==0 ){ return landmark->address().county(); } else if (key.compare("city", Qt::CaseSensitive) ==0 ){ return landmark->address().city(); } else if (key.compare("district", Qt::CaseSensitive) ==0 ){ return landmark->address().district(); } else if (key.compare("street", Qt::CaseSensitive) ==0 ){ return landmark->address().street(); } else if (key.compare("postcode", Qt::CaseSensitive) ==0 ){ return landmark->address().postcode(); } Q_ASSERT(false);//It shouldn't be possible to get here return QVariant(); } void setLandmarkAttribute(QLandmark *landmark, const QString &key, const QVariant &value) { if (key.compare("name",Qt::CaseSensitive) == 0) { landmark->setName(value.toString()); return; } else if (key.compare("description", Qt::CaseSensitive) == 0) { landmark->setDescription(value.toString()); return; } else if (key.compare("iconUrl",Qt::CaseSensitive) ==0) { landmark->setIconUrl(QUrl(value.toUrl())); return; } else if (key.compare("radius", Qt::CaseSensitive) == 0) { landmark->setRadius(value.toReal()); return; } else if (key.compare("phoneNumber", Qt::CaseSensitive) == 0) { landmark->setPhoneNumber(value.toString()); return; } else if (key.compare("url", Qt::CaseSensitive) ==0 ) { landmark->setUrl(QUrl(value.toUrl())); return; } else if (key.compare("latitude", Qt::CaseSensitive)== 0) { QGeoCoordinate coord = landmark->coordinate(); coord.setLatitude(value.toDouble()); landmark->setCoordinate(coord); return; } else if (key.compare("longitude", Qt::CaseSensitive) ==0) { QGeoCoordinate coord = landmark->coordinate(); coord.setLongitude(value.toDouble()); landmark->setCoordinate(coord); return; } else if (key.compare("altitude", Qt::CaseSensitive) ==0) { QGeoCoordinate coord = landmark->coordinate(); coord.setAltitude(value.toDouble()); landmark->setCoordinate(coord); return; } else if (key.compare("country", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setCountry(value.toString()); landmark->setAddress(address); return; } else if (key.compare("countryCode", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setCountryCode(value.toString()); landmark->setAddress(address); return; } else if (key.compare("state", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setState(value.toString()); landmark->setAddress(address); return; } else if (key.compare("county", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setCounty(value.toString()); landmark->setAddress(address); return; } else if (key.compare("city", Qt::CaseSensitive) == 0 ){ QGeoAddress address = landmark->address(); address.setCity(value.toString()); landmark->setAddress(address); return; } else if (key.compare("district", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setDistrict(value.toString()); landmark->setAddress(address); return; } else if (key.compare("street", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setStreet(value.toString()); landmark->setAddress(address); return; } else if (key.compare("postcode", Qt::CaseSensitive) ==0 ){ QGeoAddress address = landmark->address(); address.setPostcode(value.toString()); landmark->setAddress(address); return; } Q_ASSERT(false);//it shouldn't be possible to get here } /* \internal Returns true if value is in between min and max(inclusive of min and max) */ bool inBetween(double value, double min, double max) { if((min < value || qFuzzyCompare(value,min)) && (value < max || qFuzzyCompare(value,max))) return true; else return false; } /* \internal Returns true if value is outside the range from min to max. Values at exactly min or max are considered outside the range. */ bool outside(double value, double min, double max) { if ((value < min || qFuzzyCompare(value,min)) || (value > max || qFuzzyCompare(value,max))) return true; else return false; } double normalizeLongitude(double degrees) { double newDegree = degrees; while (newDegree <= -180) newDegree += 360; while (newDegree > 180) newDegree -= 360; return newDegree; } double normalizeLatitude(double degrees) { double newDegree = degrees; while (newDegree < -90) newDegree = -90; while (newDegree > 90) newDegree = 90; return newDegree; } void shiftCoordinate(QGeoCoordinate *coord,double bearing, double distance) { if (!coord) return; //convert from degrees to radians double lat1= coord->latitude() * M_PI / 180; double long1 = coord->longitude() * M_PI / 180; double bear = bearing * M_PI / 180; double lat2 = asin(sin(lat1) * cos(distance/(EARTH_MEAN_RADIUS *1000)) + cos(lat1) * sin(distance/(EARTH_MEAN_RADIUS*1000)) * cos(bear)); double long2 = long1 + atan2(sin(bear) * sin(distance/(EARTH_MEAN_RADIUS*1000)) * cos(lat1), cos(distance/(EARTH_MEAN_RADIUS * 1000)) - sin(lat1) * sin(lat2)); //convert from radians to degrees lat2 = lat2 * 180.0 / M_PI; long2 = long2 * 180.0 / M_PI; coord->setLatitude(normalizeLatitude(lat2)); coord->setLongitude(normalizeLongitude(long2)); } class LandmarkPoint { public: QGeoCoordinate coordinate; QLandmarkId landmarkId; }; int compareDistance(const QGeoCoordinate &a, const QGeoCoordinate &b, const QGeoCoordinate &c) { int result = 0; if (a.isValid()) { if (b.isValid()) { qreal da = c.distanceTo(a); qreal db = c.distanceTo(b); if (qFuzzyCompare(da,db)) { result = 0; } else if (da < db) { result = -1; } else if (da > db) { result = 1; } } else { result = -1; } } else { if (b.isValid()) { result = 1; } else { result = 0; } } return result; } void addSortedPoint(QList* sorted, const LandmarkPoint& point, const QGeoCoordinate ¢er) { for (int i = 0; i < sorted->size(); i++) { // check to see if the new landmark should be inserted here int comparison = compareDistance(sorted->at(i).coordinate, point.coordinate,center); if (comparison > 0) { sorted->insert(i, point); return; } } // hasn't been inserted yet? append to the list. sorted->append(point); } //query must have selected columns: id, latitude, longitude QList sortQueryByDistance(QSqlQuery *query, const QLandmarkProximityFilter &proximityFilter, QLandmarkManager::Error * error, QString *errorString, const QString &managerUri, QueryRun * queryRun =0){ QList result; QList sortedPoints; LandmarkPoint point; qreal radius = proximityFilter.radius(); QGeoCoordinate center = proximityFilter.center(); while(query->next()) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; return QList(); } point.coordinate.setLatitude(query->value(1).toDouble()); point.coordinate.setLongitude(query->value(2).toDouble()); point.landmarkId.setManagerUri(managerUri); point.landmarkId.setLocalId(QString::number(query->value(0).toInt())); if (radius < 0 || (point.coordinate.distanceTo(center) < radius) || qFuzzyCompare(point.coordinate.distanceTo(center), radius)) { addSortedPoint(&sortedPoints,point,center); } } for (int i=0;i < sortedPoints.count(); ++i) { result << sortedPoints.at(i).landmarkId; } return result; } bool executeQuery(QSqlQuery *query, const QString &statement, const QMap &bindValues, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(query != NULL); Q_ASSERT(error); Q_ASSERT(errorString); bool success = false; enum {Prepare =0 , Execute=1}; for(int stage=Prepare; stage <= Execute; ++stage) { if ( stage == Prepare) { if (bindValues.count() != 0) success = query->prepare(statement); else success = true; } else { // stage == Execute if (bindValues.count() != 0) success = query->exec(); else success = query->exec(statement); } if (!success) { QString errorText; errorText = "Problem: Could not %1 statement: %2" "Reason: %3" "Parameters: %4\n"; QString parameters; QStringList keys = bindValues.keys(); if (keys.count() > 0) { for(int i = 0; i < keys.count(); ++i) { parameters.append(QString("\n\t[:") + keys.at(i) + "]: " + bindValues.value(keys.at(i)).toString()); } } else { parameters = "None"; } int result = query->lastError().number(); if (result == 26 || result == 11) {//SQLILTE_NOTADB || SQLITE_CORRUPT *error = QLandmarkManager::UnknownError; } else if ( result == 8) {//SQLITE_READONLY *error = QLandmarkManager::PermissionsError; } else { *error = QLandmarkManager::UnknownError; } *errorString = errorText.arg(stage == Prepare ?"prepare":"execute") .arg(statement) .arg(query->lastError().text()) .arg(parameters); query->finish(); query->clear(); return false; } QStringList keys = bindValues.keys(); if (stage == Prepare && bindValues.count()!=0) { foreach(const QString &key, keys) query->bindValue(QString(":") + key,bindValues.value(key)); } } *error = QLandmarkManager::NoError; *errorString =""; return true; } QString queryStringForRadius(const QGeoCoordinate &coord, qreal radius) { Q_UNUSED(radius); Q_UNUSED(coord); return "SELECT id, latitude, longitude FROM landmark;"; } QString landmarkIdsDefaultQueryString() { return QString("SELECT id, latitude, longitude FROM landmark "); } QString landmarkIdsQueryString(const QList &ids) { QString queryString = "SELECT id, latitude, longitude FROM landmark WHERE id IN ("; foreach(const QLandmarkId &id, ids) { queryString += id.localId() += ","; } if (ids.count() > 0) queryString.chop(1); queryString += ") "; return queryString; } QString landmarkIdsNameQueryString(const QLandmarkNameFilter &filter) { if (filter.matchFlags() & QLandmarkFilter::MatchCaseSensitive) return QString("SELECT id FROM landmark WHERE name = \"%1\" ").arg(filter.name()); else return QString("SELECT id FROM landmark WHERE name LIKE \"%1\" ").arg(filter.name()); } QString landmarkIdsCategoryQueryString(const QLandmarkCategoryFilter &filter) { return QString("SELECT landmarkId FROM landmark_category WHERE categoryId=%1 ").arg(filter.categoryId().localId()); } QString landmarkIdsBoxQueryString(const QLandmarkBoxFilter &filter) { double tly = filter.boundingBox().topLeft().latitude(); double bry = filter.boundingBox().bottomRight().latitude(); double tlx = filter.boundingBox().topLeft().longitude(); double brx = filter.boundingBox().bottomRight().longitude(); //note: it is already assumed tly > bry bool lonWrap = (tlx > brx); QString queryString = "SELECT id, latitude, longitude FROM landmark WHERE ("; //TODO: handle case where the poles are covered by the bounding box queryString += QString::number(bry); queryString += " <= latitude AND latitude <= "; queryString += QString::number(tly); queryString += ") AND ("; if (lonWrap) { queryString += QString::number(tlx - 0.001); queryString += " <= longitude OR longitude <= "; queryString += QString::number(brx + 0.001); } else { queryString += QString::number(tlx - 0.001); queryString += " <= longitude AND longitude <= "; queryString += QString::number(brx + 0.001); } queryString += ") "; return queryString; } bool removeLandmarkHelper(const QString &connectionName, const QLandmarkId &landmarkId, QLandmarkManager::Error *error, QString *errorString, const QString &managerUri) { Q_ASSERT(error); Q_ASSERT(errorString); if (landmarkId.managerUri() != managerUri) { if (error) *error = QLandmarkManager::LandmarkDoesNotExistError; if (errorString) *errorString = "Landmark id comes from different landmark manager."; return false; } QSqlDatabase db = QSqlDatabase::database(connectionName); QString q0 = QString("SELECT 1 FROM landmark WHERE id = %1;").arg(landmarkId.localId()); QSqlQuery query(q0, db); if (!query.next()) { if (error) *error = QLandmarkManager::LandmarkDoesNotExistError; if (errorString) *errorString = QString("Landmark with local id, %1, does not exist in database").arg(landmarkId.localId()); return false; } QStringList queryStrings; queryStrings << "DELETE FROM landmark WHERE id = :lmId;"; queryStrings << "DELETE FROM landmark_category WHERE landmarkId = :lmId;"; queryStrings << "DELETE FROM landmark_attribute WHERE landmarkId=:lmId"; foreach(const QString &queryString, queryStrings) { if(!query.prepare(queryString)) { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to prepare statement: %1\nReason:%2") .arg(query.lastQuery()) .arg(query.lastError().text()); return false; } query.bindValue(":lmId", landmarkId.localId()); if (!query.exec()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to execute statement: %1\nReason: %2") .arg(query.lastQuery()) .arg(query.lastError().text()); return false; } } *error = QLandmarkManager::NoError; *errorString =""; return true; } bool categoryNameCompare(const QLandmarkCategory &cat1, const QLandmarkCategory &cat2) { return (cat1.name() < cat2.name()); } } ///////////////////////////////////////////////////////////// /////////////// Database Operation functions /////////////// ///////////////////////////////////////////////////////////// using namespace DatabaseOperationsHelpers; DatabaseOperations::DatabaseOperations() : connectionName(QString()), managerUri(QString()), queryRun(0) { } QLandmark DatabaseOperations::retrieveLandmark(const QLandmarkId &landmarkId, QLandmarkManager::Error *error, QString *errorString) const { Q_ASSERT(error); Q_ASSERT(errorString); //it is assumed the connection name is valid when this call is made. QSqlDatabase db = QSqlDatabase::database(connectionName,false); QString uri = managerUri; if (landmarkId.managerUri() != uri) { if (error) *error = QLandmarkManager::LandmarkDoesNotExistError; if (errorString) *errorString = "Landmark id comes from different landmark manager."; return QLandmark(); } if (landmarkId.localId().isEmpty()) { *error = QLandmarkManager::LandmarkDoesNotExistError; *errorString = "Landmark local id is empty"; return QLandmark(); } QLandmark lm; QStringList columns; columns << "name"; columns << "latitude"; columns << "longitude"; columns << "altitude"; if (queryRun && queryRun->isCanceled) { return QLandmark(); } QString queryString = QString("SELECT %1 FROM landmark WHERE id = %2;").arg(columns.join(",")).arg(landmarkId.localId()); QSqlQuery query1(db); if (!query1.exec(queryString)) { if (error) *error = QLandmarkManager::BadArgumentError; if (errorString) *errorString = QString("Query Failed: \n Query: %1 \n Reason: %2").arg(query1.lastQuery()).arg(query1.lastError().text()); return QLandmark(); } if (queryRun && queryRun->isCanceled) { return QLandmark(); } bool found=false; while (query1.next()) { if (found) { if (error) *error = QLandmarkManager::UnknownError; if (errorString) *errorString = QString("Landmark database is corrupted. Two landmarks were found with the same id: %1") .arg(landmarkId.localId()); qWarning() << "Non-unique primary key in table \"landmark\""; return QLandmark(); } else { found = true; } if (!query1.value(0).isNull()) { lm.setName(query1.value(0).toString()); } bool ok; QGeoCoordinate coord; if (!query1.value(1).isNull()) { coord.setLatitude(query1.value(1).toDouble(&ok)); if (!ok) { *error = QLandmarkManager::UnknownError; *errorString = QString("Landmark database is corrupted. Latitude is not a double for landmark id: %1") .arg(landmarkId.localId()); return QLandmark(); } } if (!query1.value(2).isNull()) { coord.setLongitude(query1.value(2).toDouble(&ok)); if (!ok) { *error = QLandmarkManager::UnknownError; *errorString = QString("Landmark database is corrupted. Longitude is not a double for landmark id: %1") .arg(landmarkId.localId()); return QLandmark(); } } if (!query1.value(3).isNull()) { coord.setAltitude(query1.value(3).toDouble(&ok)); if (!ok) { *error = QLandmarkManager::UnknownError; *errorString = QString("Landmark database is corrupted. Altitude is not a double for landmark id: %1") .arg(landmarkId.localId()); return QLandmark(); } } lm.setCoordinate(coord); } if (found) { lm.setLandmarkId(landmarkId); QString q2 = QString("SELECT categoryId FROM landmark_category WHERE landmarkId = %1;").arg(landmarkId.localId()); QSqlQuery query2(db); if (!query2.exec(q2)) { if (error) *error = QLandmarkManager::BadArgumentError; if (errorString) *errorString = QString("Query Failed: \n Query: %1 \n Reason: %2").arg(query2.lastQuery()).arg(query2.lastError().text()); return QLandmark(); } while (query2.next()) { if (queryRun && queryRun->isCanceled) { return QLandmark(); } QLandmarkCategoryId id; id.setManagerUri(uri); id.setLocalId(query2.value(0).toString()); lm.addCategoryId(id); } query2.clear(); query2.finish(); QMap bindValues; bindValues.insert("lmId", landmarkId.localId()); if (!executeQuery(&query2,"SELECT key,value FROM landmark_attribute WHERE landmarkId = :lmId",bindValues,error,errorString)){ return QLandmark(); } while(query2.next()) { QString key = query2.value(0).toString(); if (coreGenericAttributes.contains(key)) { //TODO: optimization setLandmarkAttribute(&lm, key, query2.value(1)); } else { qWarning() << "Database is corrupt it contains an unrecognised generic key: " << key; } } if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } else { Q_ASSERT(error); Q_ASSERT(errorString); *error = QLandmarkManager::LandmarkDoesNotExistError; *errorString = QString("Landmark with id, %1, does not exist.").arg(landmarkId.localId()); } return lm; } QList DatabaseOperations::landmarkIds(const QLandmarkFilter& filter, const QList& sortOrders, int limit, int offset, QLandmarkManager::Error *error, QString *errorString) const { Q_ASSERT(error); Q_ASSERT(errorString); *error = QLandmarkManager::NoError; *errorString =""; QList result; bool alreadySorted = false; for (int i=0; i < sortOrders.count(); ++i) { if (sortOrders.at(i).type() == QLandmarkSortOrder::NameSort) { QLandmarkNameSort nameSort = sortOrders.at(i); if (nameSort.caseSensitivity() == Qt::CaseSensitive) { *error = QLandmarkManager::NotSupportedError; *errorString = "Case sensitive sorting is not supported"; return QList(); } } } QSqlDatabase db = QSqlDatabase::database(connectionName, false); if (!db.isValid()) { if(error) *error = QLandmarkManager::UnknownError; if(errorString) *errorString = QString("Invalid QSqlDatabase object used in landmark retrieval, " "connection name = %1").arg(connectionName); return result; } if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; return QList(); } bool idsFound = false; QString queryString; QMap bindValues; switch (filter.type()) { case QLandmarkFilter::InvalidFilter: break; case QLandmarkFilter::DefaultFilter: queryString = landmarkIdsDefaultQueryString(); break; case QLandmarkFilter::AttributeFilter: { QLandmarkAttributeFilter attributeFilter = filter; QStringList filterKeys = attributeFilter.attributeKeys(); if (filterKeys.count() > 0) { QSqlQuery query(db); QMap bindValues; QString key; QList lmIds; bool selectAll =false; foreach(const QString key, filterKeys) { if (!supportedSearchableAttributes.contains(key)) { *error = QLandmarkManager::NotSupportedError; *errorString = QString("Attribute key not searchable: ").arg(key); return QList(); } } QVariant attributeValue; //try to see if we need to select all landmarks //ie OR operation with a single invalid QVariant parameter //AND operation with all invalid QVariant parameter for ( int i = 0; i < filterKeys.count(); ++i) { key = filterKeys.at(i); attributeValue = attributeFilter.attribute(key).toString(); if (!attributeFilter.attribute(key).isValid()) { if( attributeFilter.operationType() == QLandmarkAttributeFilter::OrOperation) { selectAll = true; break; } else { selectAll = true; continue; } } else { if (attributeFilter.operationType() == QLandmarkAttributeFilter::OrOperation) continue; else{ selectAll = false; break; } } } if (selectAll) { queryString = QString("SELECT id FROM landmark"); break; } else { if (attributeFilter.operationType() == QLandmarkAttributeFilter::AndOperation) { QStringList lmLocalIds; if (attributeFilter.attributeKeys().contains("name")) { QLandmarkNameFilter nameFilter; nameFilter.setName(attributeFilter.attribute("name").toString()); nameFilter.setMatchFlags(attributeFilter.matchFlags("name")); QList sortOrders; QList lmIds = landmarkIds(nameFilter,sortOrders,limit,offset,error,errorString); if (*error != QLandmarkManager::NoError) { return QList(); } foreach(const QLandmarkId &id, lmIds){ lmLocalIds << id.localId(); } filterKeys.removeAll("name"); } else { bindValues.insert("key", filterKeys.at(0)); queryString = QString("SELECT landmarkId FROM %1 WHERE key = :key"); queryString = queryString.arg("landmark_attribute"); if (!executeQuery(&query, queryString, bindValues,error,errorString)) { return QList(); } while(query.next()) { lmLocalIds << query.value(0).toString(); } } if (filterKeys.count() > 0) { QLandmarkId id; id.setManagerUri(managerUri); queryString = QString("SELECT key, value FROM %1 WHERE landmarkId=:lmId"); queryString = queryString.arg("landmark_attribute"); for (int i=0; i < lmLocalIds.count(); ++i) { bindValues.clear(); bindValues.insert("lmId", lmLocalIds.at(i)); if (!executeQuery(&query, queryString, bindValues, error, errorString)) { return QList(); } QMap lmAttributes; while(query.next()) { lmAttributes.insert(query.value(0).toString(), query.value(1)); } bool isMatch = true; QVariant lmAttributeValue; QVariant filterAttributeValue; foreach(const QString &filterAttributeKey, filterKeys) { if (!lmAttributes.contains(filterAttributeKey)) { isMatch = false; break; } if (!attributeFilter.attribute(filterAttributeKey).isValid()) { continue; } else { lmAttributeValue = lmAttributes.value(filterAttributeKey); filterAttributeValue = attributeFilter.attribute(filterAttributeKey); if (filterAttributeValue.type() == QVariant::String) { if (matchString(lmAttributeValue.toString(), filterAttributeValue.toString(), attributeFilter.matchFlags(filterAttributeKey))) { continue; } } else { if (lmAttributeValue == filterAttributeValue) { continue; } } //didn't find a match isMatch = false; break; } } if (isMatch) { id.setLocalId(lmLocalIds.at(i)); result << id; } } } else { QLandmarkId id; id.setManagerUri(managerUri); foreach(const QString &localId, lmLocalIds) { id.setLocalId(localId); result << id; } } } else { if (attributeFilter.attributeKeys().contains("name")) { QLandmarkNameFilter nameFilter; nameFilter.setName(attributeFilter.attribute("name").toString()); nameFilter.setMatchFlags(attributeFilter.matchFlags("name")); QList sortOrders; QList lmIds = landmarkIds(nameFilter,sortOrders,limit,offset,error,errorString); if (*error != QLandmarkManager::NoError) { return QList(); } result << lmIds; filterKeys.removeAll("name"); } queryString = QString("SELECT landmarkId FROM %1 WHERE "); queryString = queryString.arg("landmark_attribute"); QVariant attributeValue; for (int i=0; i < filterKeys.count(); ++i) { key = filterKeys.at(i); attributeValue = attributeFilter.attribute(key); queryString.append(QString("(key = :key_") + key + " "); bindValues.insert(QString("key_")+key, key); if (attributeValue.isValid()) { queryString.append("AND "); if (attributeValue.type() == QVariant::String) { if (attributeFilter.matchFlags(key) == QLandmarkFilter::MatchExactly) { queryString.append("value = :" + key + " "); bindValues.insert(key, attributeValue); } else { queryString.append("value LIKE :" + key + " "); if ((attributeFilter.matchFlags(key) & 3) == QLandmarkFilter::MatchEndsWith) bindValues.insert(key, QString("%") + attributeValue.toString()); else if ((attributeFilter.matchFlags(key) & 3) == QLandmarkFilter::MatchStartsWith) bindValues.insert(key, attributeValue.toString() + "%"); else if ((attributeFilter.matchFlags(key) & 3) == QLandmarkFilter::MatchContains) bindValues.insert(key, QString("%") + attributeValue.toString() + "%"); else if (attributeFilter.matchFlags(key) == QLandmarkFilter::MatchFixedString) bindValues.insert(key, attributeValue.toString()); } } else { queryString.append("value = :" + key + " "); bindValues.insert(key, attributeValue); } } queryString.append(")"); if (i < (filterKeys.count() -1)) { queryString.append(" OR "); } } queryString.append(";"); if (!executeQuery(&query, queryString, bindValues,error,errorString)) { return QList(); } QLandmarkId landmarkId; while(query.next()) { landmarkId.setLocalId(query.value(0).toString()); landmarkId.setManagerUri(managerUri); if (!result.contains(landmarkId)) result << landmarkId; } } } } idsFound = true; break; } case QLandmarkFilter::NameFilter: { QLandmarkNameFilter nameFilter; nameFilter = filter; if (DatabaseOperations::filterSupportLevel(nameFilter)== QLandmarkManager::NoSupport) { *error = QLandmarkManager::NotSupportedError; *errorString = "The name filter's configuration is not supported"; return result; } queryString = QString("SELECT id FROM landmark WHERE "); QString nameKey = "name"; QString nameValue = nameFilter.name(); if (nameValue.isEmpty()) { if (nameFilter.matchFlags() == QLandmarkFilter::MatchExactly || nameFilter.matchFlags() == QLandmarkFilter::MatchFixedString) { queryString.append(nameKey + " IS NULL "); } else { queryString = "SELECT id from landmark "; } } else if (nameFilter.matchFlags() == QLandmarkFilter::MatchExactly) { queryString.append(nameKey + " = :" + nameKey + " "); bindValues.insert(nameKey, nameValue); } else { queryString.append(nameKey + " LIKE :" + nameKey + " "); if ((nameFilter.matchFlags() & 3) == QLandmarkFilter::MatchEndsWith) bindValues.insert(nameKey, QString("%") + nameValue ); else if ((nameFilter.matchFlags() & 3) == QLandmarkFilter::MatchStartsWith) bindValues.insert(nameKey, nameValue + "%"); else if ((nameFilter.matchFlags() & 3) == QLandmarkFilter::MatchContains) bindValues.insert(nameKey, QString("%") + nameValue + "%"); else if (nameFilter.matchFlags() == QLandmarkFilter::MatchFixedString) bindValues.insert(nameKey, nameValue); } break; } case QLandmarkFilter::LandmarkIdFilter: { QLandmarkIdFilter idFilter = filter; //provide a query string exeecute so to that sqlite can handle sorting by name queryString = landmarkIdsQueryString(idFilter.landmarkIds()); break; } case QLandmarkFilter::CategoryFilter: { QSqlQuery query(db); QMap bindValues; QLandmarkCategoryFilter categoryFilter = filter; QLandmarkCategoryId categoryId = categoryFilter.categoryId(); if (categoryId.managerUri() != managerUri) { *error = QLandmarkManager::NoError; *errorString = ""; return result; } else if (categoryId.localId().isEmpty()) { *error = QLandmarkManager::NoError; *errorString = ""; return result; } bindValues.clear(); bindValues.insert("catId",categoryId.localId()); if (!executeQuery(&query,"SELECT * from category WHERE id = :catId", bindValues, error, errorString)){ return result; } if (!query.next()) { *error = QLandmarkManager::NoError; *errorString = ""; return result; } queryString = landmarkIdsCategoryQueryString(categoryFilter); break; } case QLandmarkFilter::ProximityFilter: { QLandmarkProximityFilter proximityFilter = filter; QGeoCoordinate center = proximityFilter.center(); if ( (qIsNaN(center.latitude()) || qIsNaN(center.longitude()) || !isValidLat(center.latitude()) || !isValidLong(center.longitude())) ) { *error = QLandmarkManager::BadArgumentError; *errorString = "Center coordinate of proximity filter is invalid"; return result; } if (proximityFilter.radius() < 0) { queryString = ::landmarkIdsDefaultQueryString(); break; } //fall through if we have a radius, we can use a box filter //to quickly cull out landmarks } case QLandmarkFilter::BoxFilter: { QLandmarkBoxFilter boxFilter; if (filter.type() == QLandmarkFilter::BoxFilter) { boxFilter = filter; } else { QGeoCoordinate center; double radius; //use double since these are going to be usd in calculation with lat/long if(filter.type() == QLandmarkFilter::ProximityFilter) { QLandmarkProximityFilter proximityFilter; proximityFilter = filter; center = proximityFilter.center(); radius = proximityFilter.radius(); } //for a given latitude, find the how many degrees longitude a given distance could possibly cover. //for a given center, we "shift" it north or south by the radius then find //how many degrees longitude E or W the given radius could cover. double maxLongAbs = 0.0; if (center.latitude() > 0.0 ) { //coordinate must be in northern hemisphere so "shift" north first QGeoCoordinate coord = center; shiftCoordinate(&coord,0, radius); shiftCoordinate(&coord, 270, radius); maxLongAbs = qAbs(center.longitude() - coord.longitude()); double maxLat = center.latitude() + radius / ( 2.0 * M_PI * EARTH_MEAN_RADIUS *1000) *360; if (maxLat > 90.0 || qFuzzyCompare(maxLat, 90.0)) { *error = QLandmarkManager::BadArgumentError; *errorString = "The proximity filter covers the north pole which is not allowed"; result.clear(); return result; } } else { //coordinate must be in southerh hemisphere so "shift" south first QGeoCoordinate coord = center; shiftCoordinate(&coord,180, radius); shiftCoordinate(&coord, 90, radius); maxLongAbs = qAbs(center.longitude() - coord.longitude()); double minLat = center.latitude() - radius / ( 2.0 * M_PI * EARTH_MEAN_RADIUS *1000) *360; if (minLat < -90.0 || qFuzzyCompare(minLat, -90.0)) { *error = QLandmarkManager::BadArgumentError; *errorString = "The proximity filter covers the south pole which is not allowed"; result.clear(); return result; } } if (maxLongAbs > 180) maxLongAbs = 360.0 - maxLongAbs; QGeoCoordinate topLeft = center; shiftCoordinate(&topLeft, 0, radius); topLeft.setLongitude(normalizeLongitude(topLeft.longitude() - maxLongAbs)); QGeoCoordinate bottomRight = center; shiftCoordinate(&bottomRight, 180, radius); bottomRight.setLongitude(normalizeLongitude(bottomRight.longitude()+ maxLongAbs)); QGeoBoundingBox box; box.setTopLeft(topLeft); box.setBottomRight(bottomRight); boxFilter.setBoundingBox(box); //TODO: handle poles } if (!boxFilter.boundingBox().isValid()) { if (error) *error = QLandmarkManager::BadArgumentError; if (errorString) *errorString = QString("Invalid bounding box for landmark box filter"); return result; } //TODO: handle box covering poles if (boxFilter.boundingBox().topLeft().latitude() < boxFilter.boundingBox().bottomRight().latitude()) { if (error) *error = QLandmarkManager::BadArgumentError; if (errorString) *errorString = QString("Box filter top left coordinate latitude, %1, is less than " "bottom right coordinate latitude, %2") .arg(boxFilter.boundingBox().topLeft().latitude()) .arg(boxFilter.boundingBox().bottomRight().latitude()); return result; } queryString = landmarkIdsBoxQueryString(boxFilter); break; } case QLandmarkFilter::IntersectionFilter: { QLandmarkIntersectionFilter intersectionFilter = filter; QList filters = intersectionFilter.filters(); if (filters.size() == 0) { //do nothing } else if (filters.size() == 1) { result = landmarkIds( filters.at(0), QList(), -1, 0, error, errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } } else { bool haveProximityFilter = false; QLandmarkProximityFilter proximityFilter; int originalFilterCount = filters.count(); for (int i=0; i < originalFilterCount ; ++i) { if (filters.at(i).type() == QLandmarkFilter::ProximityFilter) { proximityFilter = filters.takeAt(i); haveProximityFilter = true; break; } } QSet ids; QList firstResult = landmarkIds(filters.at(0), QList(), -1, 0, error, errorString); ids = firstResult.toSet(); for (int i = 1; i < filters.size(); ++i) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; result.clear(); return result; } QList subResult = landmarkIds(filters.at(i), QList(), -1, 0, error, errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } ids &= subResult.toSet(); } QList idList = ids.toList(); if (haveProximityFilter) { QList sortedPoints; QMap bindValues; QSqlQuery idsQuery(db); executeQuery(&idsQuery,landmarkIdsQueryString(idList),bindValues,error,errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } result = sortQueryByDistance(&idsQuery,proximityFilter,error,errorString,managerUri,queryRun); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } } else { result << idList; } } idsFound = true; } break; case QLandmarkFilter::UnionFilter: { QLandmarkUnionFilter unionFilter = filter; QSet ids; QList filters = unionFilter.filters(); if (filters.size() == 0) { //do nothing } else if (filters.size() == 1) { result = landmarkIds(filters.at(0), QList(), -1, 0, error, errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } } else { for (int i = 0; i < filters.size(); ++i) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; result.clear(); return result; } QList subResult = landmarkIds(filters.at(i), QList(), -1, 0, error, errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } for (int j = 0; j < subResult.size(); ++j) { if (subResult.at(j).isValid()) ids.insert(subResult.at(j).localId()); } } QList idList = ids.toList(); for (int i = 0; i < idList.size(); ++i) { QLandmarkId id; id.setManagerUri(managerUri); id.setLocalId(idList.at(i)); result << id; } } idsFound = true; } break; default: if(error) *error = QLandmarkManager::BadArgumentError; if(errorString) *errorString = QString("Unrecognised filter type"); break; } if (!idsFound) { if (sortOrders.length() == 1 && sortOrders.at(0).type() == QLandmarkSortOrder::NameSort) { QLandmarkNameSort nameSort = sortOrders.at(0); queryString.append("ORDER BY name "); if (nameSort.caseSensitivity() == Qt::CaseInsensitive) queryString.append("COLLATE NOCASE "); if (nameSort.direction() == Qt::AscendingOrder) queryString.append("ASC "); else queryString.append("DESC "); alreadySorted = true; } queryString.append(";"); QSqlQuery query(db); if (!executeQuery(&query, queryString,bindValues,error,errorString)) { return result; } QLandmarkId id; while (query.next()) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; return QList(); } if (filter.type() == QLandmarkFilter::BoxFilter) { //need to do a fuzzy compare on the coordinates (using inBetween() and outside() fns) //since sqlite doeesn't handle comparison of floating point numbers QLandmarkBoxFilter boxFilter = filter; double maxLat = boxFilter.boundingBox().topLeft().latitude(); double minLat = boxFilter.boundingBox().bottomRight().latitude(); double minLong; double maxLong; //special edge case if the bounding box crosses the dateline bool longWrap = boxFilter.boundingBox().topLeft().longitude() > boxFilter.boundingBox().bottomRight().longitude(); if (longWrap) { minLong = boxFilter.boundingBox().bottomRight().longitude(); maxLong = boxFilter.boundingBox().topLeft().longitude(); } else { minLong = boxFilter.boundingBox().topLeft().longitude(); maxLong = boxFilter.boundingBox().bottomRight().longitude(); } do { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation was canceled"; return QList(); } if (inBetween(query.value(1).toDouble(),minLat, maxLat) && (longWrap) ? outside(query.value(2).toDouble(),minLong, maxLong) : inBetween(query.value(2).toDouble(),minLong, maxLong)) { id.setManagerUri(managerUri); id.setLocalId(QString::number(query.value(0).toInt())); result << id; } } while (query.next()); } else if ( filter.type() == QLandmarkFilter::ProximityFilter) { QLandmarkProximityFilter proximityFilter; proximityFilter = filter; query.previous(); result << sortQueryByDistance(&query, proximityFilter,error,errorString,managerUri,queryRun); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } } else { id.setManagerUri(managerUri); id.setLocalId(QString::number(query.value(0).toInt())); result << id; } } } //TODO: optimize if (offset >= result.count()) { result.clear(); return result; } if (!alreadySorted && sortOrders.count() > 0 ) { //TODO: optimize this QList landmarks; QLandmark landmark; for (int i=0; i < result.count(); ++i) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; return QList(); } landmark = retrieveLandmark(result.at(i),error,errorString); if (*error != QLandmarkManager::NoError) { result.clear(); return result; } landmarks.append(landmark); } result = QLandmarkManagerEngineSqlite::sortLandmarks(landmarks, sortOrders); } if (offset < 0 ) offset = 0; return result.mid(offset, limit); } QList DatabaseOperations::landmarks(const QLandmarkFilter& filter, const QList& sortOrders, int limit, int offset, QLandmarkManager::Error *error, QString *errorString) const { QList result; QSqlDatabase db = QSqlDatabase::database(connectionName, false); if (!db.isValid()) { if(error) *error = QLandmarkManager::UnknownError; if(errorString) *errorString = QString("Invalid QSqlDatabase object used in landmark retrieval, " "connection name = %1").arg(connectionName); return result; } QList ids = landmarkIds(filter, sortOrders, limit, offset, error, errorString); if (error && *error != QLandmarkManager::NoError) { return result; } bool needAll = false; if (filter.type() == QLandmarkFilter::LandmarkIdFilter) { QLandmarkIdFilter idFilter = filter; } QLandmark lm; foreach(const QLandmarkId &id, ids) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation canceled"; return QList(); } lm = retrieveLandmark(id,error,errorString); if (lm.landmarkId().isValid() && *error == QLandmarkManager::NoError) { result.append(lm); } else { if (*error == QLandmarkManager::DoesNotExistError) { if (!needAll) { continue; } else { result.clear(); return result; } } else { result.clear(); return result; } } } *error = QLandmarkManager::NoError; *errorString = ""; return result; } QList DatabaseOperations::landmarks(const QList &landmarkIds, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) const { if (errorMap) errorMap->clear(); QList result; QLandmark lm; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString=""; for (int i=0; i < landmarkIds.count(); ++i){ lm = retrieveLandmark(landmarkIds.at(i),error,errorString); if (*error == QLandmarkManager::NoError) { result << lm; } else { if (errorMap) errorMap->insert(i, *error); lastError = *error; lastErrorString = *errorString; result << QLandmark(); } } *error = lastError; *errorString =lastErrorString; return result; } //Performs the save sql queries but does not handle //starting or rolling back/comitting transactions. bool DatabaseOperations::saveLandmarkHelper(QLandmark *landmark, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (!landmark->landmarkId().managerUri().isEmpty() && landmark->landmarkId().managerUri() != managerUri) { if (error) *error = QLandmarkManager::LandmarkDoesNotExistError; if (errorString) *errorString = "Landmark id comes from different landmark manager."; return false; } bool update = landmark->landmarkId().isValid(); QSqlDatabase db = QSqlDatabase::database(connectionName); QHash bindValues; if (update) { bindValues.insert("id",landmark->landmarkId().localId()); QString q0 = QString("SELECT 1 FROM landmark WHERE id = %1;").arg(landmark->landmarkId().localId()); QSqlQuery query0(q0, db); if (!query0.next()) { if (error) *error = QLandmarkManager::LandmarkDoesNotExistError; if (errorString) *errorString = "Landmark id does not exist in this landmark manager."; return false; } } if (!landmark->name().isEmpty()) bindValues.insert("name", landmark->name()); else bindValues.insert("name", QVariant()); QGeoCoordinate coord; coord = landmark->coordinate(); if (qIsNaN(coord.latitude()) && qIsNaN(coord.longitude())) { bindValues.insert("latitude", QVariant()); bindValues.insert("longitude", QVariant()); } else if (!qIsNaN(coord.latitude()) && !qIsNaN(coord.longitude()) && isValidLat(coord.latitude()) && isValidLong(coord.longitude())) { bindValues.insert("latitude", coord.latitude()); bindValues.insert("longitude", coord.longitude()); } else { *error = QLandmarkManager::BadArgumentError; *errorString = "Landmark coordinate is not valid, latitude must between -90 and 90 and longitude must be between -180 and 180, or both " "latitude and longitude are NaN"; return false; } if (!qIsNaN(coord.altitude())) bindValues.insert("altitude", coord.altitude()); else bindValues.insert("altitude",QVariant()); QString q1; QStringList keys = bindValues.keys(); if (update) { QStringList placeholderKeys = keys; for (int i=0; i < placeholderKeys.count(); ++i) { placeholderKeys[i] = placeholderKeys[i] + "= :" + placeholderKeys[i]; } q1 = QString("UPDATE landmark SET %1 WHERE id = :lmId;").arg(placeholderKeys.join(",")); bindValues.insert("lmId", landmark->landmarkId().localId()); } else { q1 = QString("REPLACE INTO landmark (%1) VALUES (%2);").arg(keys.join(",")).arg(QString(":").append(keys.join(", :"))); } QSqlQuery query1(db); if (!query1.prepare(q1)) { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to prepare statment: ") + q1 + "\nReason:" + query1.lastError().text(); return false; } foreach(const QString &key, bindValues.keys()) { query1.bindValue(QString(":").append(key), bindValues.value(key)); } if (!query1.exec()) { *error = QLandmarkManager::UnknownError; *errorString = "Unable to execute statment: " + q1 + "\nReason:" + query1.lastError().text(); return false; } QLandmarkId id; id.setManagerUri(managerUri); if (update) id.setLocalId(landmark->landmarkId().localId()); else id.setLocalId(query1.lastInsertId().toString()); QStringList lmCats; for (int i = landmark->categoryIds().size() - 1; i >= 0; --i) { QLandmarkCategoryId id = landmark->categoryIds().at(i); if (id.managerUri() == managerUri) lmCats << id.localId(); else { *error = QLandmarkManager::CategoryDoesNotExistError; *errorString = "Landmark contains category that belongs to another manager"; return false; } } QStringList queries; QString queryString; QSqlQuery catQuery(db); for (int i=0;i < lmCats.size(); ++i) { queryString = QString("SELECT id FROM category WHERE id = %1").arg(lmCats.at(i)); if (!catQuery.exec(queryString)) { return false; } if (!catQuery.next()) { if (error) *error = QLandmarkManager::CategoryDoesNotExistError; if (errorString) *errorString = "Landmark contains a category id that does not exist"; return false; } } catQuery.finish(); queries << "CREATE TEMP TABLE IF NOT EXISTS lc_refresh (i INTEGER);"; for (int i = 0; i < lmCats.size(); ++i) { queries << QString("INSERT INTO lc_refresh (i) VALUES (%1);").arg(lmCats.at(i)); } queries << QString("DELETE FROM landmark_category WHERE landmarkId = %1 AND categoryId NOT IN lc_refresh;").arg(id.localId()); queries << QString("REPLACE INTO landmark_category SELECT %1, i FROM lc_refresh;").arg(id.localId()); queries << "DROP TABLE IF EXISTS lc_refresh;"; for (int i = 0; i < queries.size(); ++i) { QSqlQuery query(db); if (!query.exec(queries.at(i))) { qWarning() << query.lastError().databaseText(); *error = QLandmarkManager::UnknownError; *errorString = "Unable to execute statment: " + query.lastQuery() + "\nReason:" + query.lastError().text(); return false; } } if (!update) { landmark->setLandmarkId(id); } QStringList attributeKeys = coreGenericAttributes; QSqlQuery query(db); foreach(const QString &key, attributeKeys) { if (!query.prepare("REPLACE INTO landmark_attribute (landmarkId,key,value) VALUES(:lmId,:key,:value)")) { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to prepare statement: %1 \nReason: %2") .arg(query.lastQuery()).arg(query.lastError().text()); return false; } query.bindValue(":lmId", landmark->landmarkId().localId()); query.bindValue(":key", key); query.bindValue(":value", getLandmarkAttribute(landmark, key)); if (!query.exec()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to execute statement: %1\nReason:%2") .arg(query.lastQuery()).arg(query.lastError().text()); return false; } } *error = QLandmarkManager::NoError; *errorString=""; return true; } bool DatabaseOperations::saveLandmark(QLandmark* landmark, QLandmarkManager::Error *error, QString *errorString) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Save landmark: unable to begin transaction, reason: %1").arg(db.lastError().text()); return false; } bool result = saveLandmarkHelper(landmark, error, errorString); if (result) db.commit(); else db.rollback(); return result; } bool DatabaseOperations::saveLandmarks(QList * landmark, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (errorMap) errorMap->clear(); QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Save landmarks: unable to begin transaction, reason: %1").arg(db.lastError().text()); if (errorMap) { for (int i=0; i < landmark->size(); ++i) errorMap->insert(i, *error); } return false; } bool noErrors = true; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString; QLandmarkManager::Error loopError; QString loopErrorString; bool result; for (int i = 0; i < landmark->size(); ++i) { loopError = QLandmarkManager::NoError; loopErrorString = ""; if (queryRun && queryRun->isCanceled) { lastError = QLandmarkManager::CancelError; lastErrorString = "Landmark save was canceled"; if (errorMap) { for (int j = i; j < landmark->size(); ++j) errorMap->insert(j, lastError); } noErrors = false; break; } QSqlQuery query(db); if (!query.exec("SAVEPOINT save")) { loopError = QLandmarkManager::UnknownError; loopErrorString = QString("Save landmarks: could not execute statement: %1\nReason:%2").arg(query.lastQuery()).arg(query.lastError().text()); result = false; } else { result = saveLandmarkHelper(&(landmark->operator [](i)), &loopError, &loopErrorString); } if (errorMap && (loopError != QLandmarkManager::NoError)) errorMap->insert(i, loopError); if (!result) { noErrors = false; lastError = loopError; lastErrorString = loopErrorString; query.exec("ROLLBACK TO SAVEPOINT save"); } else { query.exec("RELEASE SAVEPOINT save"); } } db.commit(); if (noErrors) { *error = QLandmarkManager::NoError; *errorString = ""; } else { if (error) *error = lastError; if (errorString) *errorString = lastErrorString; } return noErrors; } bool DatabaseOperations::removeLandmark(const QLandmarkId &landmarkId, QLandmarkManager::Error *error, QString *errorString) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Remove landmark: unable to begin transaction, reason: %1").arg(db.lastError().text()); return false; } bool result = removeLandmarkHelper(connectionName, landmarkId, error, errorString, managerUri); if (result) db.commit(); else db.rollback(); return result; } bool DatabaseOperations::removeLandmarks(const QList &landmarkIds, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (errorMap) errorMap->clear(); QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Remove landmars: unable to begin transaction, reason: %1").arg(db.lastError().text()); if (errorMap) { for (int i=0; i < landmarkIds.size(); ++i) errorMap->insert(i, *error); } return false; } bool noErrors = true; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString; QLandmarkManager::Error loopError; QString loopErrorString; bool result; for (int i = 0; i < landmarkIds.size(); ++i) { loopError = QLandmarkManager::NoError; loopErrorString.clear(); if (queryRun && queryRun->isCanceled) { lastError = QLandmarkManager::CancelError; lastErrorString = "Landmark remove was canceled"; if (errorMap) { for (int j = i; j < landmarkIds.size(); ++j) errorMap->insert(j, lastError); } noErrors = false; break; } QSqlQuery query(db); if (!query.exec("SAVEPOINT save")) { loopError = QLandmarkManager::UnknownError; loopErrorString = QString("Remove landmarks: could not execute statement: %1\nReason:%2").arg(query.lastQuery()).arg(query.lastError().text()); result = false; } else { result = removeLandmarkHelper(connectionName, landmarkIds.at(i), &loopError, &loopErrorString, managerUri); } if (errorMap && loopError != QLandmarkManager::NoError) errorMap->insert(i, loopError); if (!result) { noErrors = false; lastError = loopError; lastErrorString = loopErrorString; query.exec("ROLLBACK TO SAVEPOINT save"); } else { query.exec("RELEASE SAVEPOINT save"); } } db.commit(); if (noErrors) { if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } else { if (error) *error = lastError; if (errorString) *errorString = lastErrorString; } return noErrors; } QList DatabaseOperations::categoryIds(const QLandmarkNameSort &nameSort, int limit, int offset, QLandmarkManager::Error *error, QString *errorString) const { QList result; QString uri = managerUri; QSqlDatabase db = QSqlDatabase::database(connectionName); QSqlQuery query(db); QString queryString("SELECT id FROM category ORDER BY name "); if (nameSort.caseSensitivity() == Qt::CaseInsensitive) queryString.append("COLLATE NOCASE "); else { *error = QLandmarkManager::NotSupportedError; *errorString = "Case sensitive name sorting of categories is not supported"; return QList(); } if (nameSort.direction() == Qt::AscendingOrder) queryString.append("ASC;"); else queryString.append("DESC;"); if (!query.exec(queryString)) { if (error) *error = QLandmarkManager::UnknownError; if (errorString) *errorString = QString("Unable to execute query: %1 \nReason: %2").arg(query.lastQuery()).arg(query.lastError().text()); return result; } while (query.next()) { if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation was canceled"; result.clear(); return result; } QLandmarkCategoryId id; id.setManagerUri(managerUri); id.setLocalId(QString::number(query.value(0).toInt())); result << id; } //TODO: optimize if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; if (offset>= result.count()) { result.clear(); return result; } if (offset < 0) offset = 0; return result.mid(offset,limit); } QLandmarkCategory DatabaseOperations::category(const QLandmarkCategoryId &landmarkCategoryId, QLandmarkManager::Error *error, QString *errorString) const { if (!landmarkCategoryId.isValid() || landmarkCategoryId.managerUri() != managerUri) { if (error) *error = QLandmarkManager::CategoryDoesNotExistError; if (errorString) *errorString = "Category id is not valid for this manager"; return QLandmarkCategory(); } QLandmarkCategory cat; QStringList columns; columns << "name"; QSqlDatabase db = QSqlDatabase::database(connectionName); QString q1 = QString("SELECT %1 FROM category WHERE id = %2;").arg(columns.join(",")).arg(landmarkCategoryId.localId()); QSqlQuery query(q1, db); bool found = false; while (query.next()) { if (found) { // TODO set error - should never happen if (error) *error = QLandmarkManager::UnknownError; if (errorString) *errorString = "Database corruption, non-unique primary key in table \"category\""; qWarning() << "Non-unique primary key in table \"category\""; return QLandmarkCategory(); } else { found = true; } if (!query.value(0).isNull()) cat.setName(query.value(0).toString()); // TODO: category description is not a common data attribute, make it a platform specific attribute // if (!query.value(1).isNull()) // cat.setDescription(query.value(1).toString()); if (!query.value(2).isNull()) cat.setIconUrl(query.value(2).toString()); cat.setCategoryId(landmarkCategoryId); } if (!found) { *error = QLandmarkManager::CategoryDoesNotExistError; *errorString = "None of the existing categories match the given category id."; } else { query.finish(); query.clear(); QMap bindValues; bindValues.insert("catId", landmarkCategoryId.localId()); if (!executeQuery(&query,"SELECT key,value FROM category_attribute WHERE categoryId = :catId", bindValues, error, errorString)){ return QLandmarkCategory(); } while(query.next()) { QString key = query.value(0).toString(); if (coreGenericCategoryAttributes.contains(key)) { setCategoryAttribute(&cat,key,query.value(1)); } else { qWarning() << "Database is corrupt it contains an unrecognised generic key: " << key; } } *error = QLandmarkManager::NoError; *errorString = ""; } return cat; } QList DatabaseOperations::categories(const QList &landmarkCategoryIds, const QLandmarkNameSort &nameSort, int limit, int offset, QLandmarkManager::Error *error, QString *errorString, bool needAll) const { Q_ASSERT(error); Q_ASSERT(errorString); *error = QLandmarkManager::NoError; errorString->clear(); QList result; QList ids = landmarkCategoryIds; if (ids.size() == 0) { ids = categoryIds(nameSort, limit, offset, error, errorString); if (*error != QLandmarkManager::NoError) { return result; } } for (int i = 0; i < ids.size(); ++i) { *error = QLandmarkManager::NoError; (*errorString).clear(); if (errorString) if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Fetch operation was canceled"; result.clear(); return result; } QLandmarkCategory cat = category(ids.at(i), error,errorString); if (*error == QLandmarkManager::NoError) result << cat; else { if (*error == QLandmarkManager::DoesNotExistError) { if (!needAll) continue; } else { result.clear(); return result; } result.clear(); return result; } } if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; return result; } QList DatabaseOperations::categories(const QList &landmarkCategoryIds, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) const { if (errorMap) errorMap->clear(); QList result; QLandmarkCategory cat; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString =""; for (int i=0; i < landmarkCategoryIds.count(); ++i) { cat = category(landmarkCategoryIds.at(i),error,errorString); if (*error == QLandmarkManager::NoError) { result << cat; } else { result << QLandmarkCategory(); if (errorMap) errorMap->insert(i, *error); lastError = *error; lastErrorString = *errorString; } } *error = lastError; *errorString = lastErrorString; return result; } bool DatabaseOperations::saveCategoryHelper(QLandmarkCategory *category, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (category->name().isEmpty()) { *error = QLandmarkManager::BadArgumentError; *errorString = "Category name must not be empty"; return false; } if (!category->categoryId().managerUri().isEmpty() && category->categoryId().managerUri() != managerUri) { if (error) *error = QLandmarkManager::CategoryDoesNotExistError; if (errorString) *errorString = "Category id comes from different landmark manager."; return false; } bool update = category->categoryId().isValid(); QSqlDatabase db = QSqlDatabase::database(connectionName); QMap bindValues; QSqlQuery query(db); if (update) { bindValues.insert("id",category->categoryId().localId()); QString q0 = QString("SELECT 1 FROM category WHERE id = :id;"); if (!executeQuery(&query,q0, bindValues,error,errorString)) { return false; } if (!query.next()) { if (error) *error = QLandmarkManager::CategoryDoesNotExistError; if (errorString) *errorString = "Category id does not exist in this landmark manager."; return false; } bindValues.clear(); } if (!category->name().isEmpty()) bindValues.insert("name", category->name()); else bindValues.insert("name", QVariant()); QMap tempBindValues; tempBindValues.insert("name", bindValues.value("name")); if (!executeQuery(&query, "SELECT id FROM category WHERE name = :name", tempBindValues,error,errorString)) { return false; } if (query.next()) { if (!update || (update && (query.value(0).toString() != category->categoryId().localId()))) { *error = QLandmarkManager::AlreadyExistsError; *errorString = QString("Category with name: %1 already exists").arg(category->name()); return false; } } QString q1; QStringList keys = bindValues.keys(); if (update) { QStringList placeholderKeys = keys; for (int i=0; i < placeholderKeys.count(); ++i) { placeholderKeys[i] = placeholderKeys[i] + "= :" + placeholderKeys[i]; } q1 = QString("UPDATE category SET %1 WHERE id = :id;").arg(placeholderKeys.join(",")); bindValues.insert("id",category->categoryId().localId()); } else { q1 = QString("REPLACE INTO category (%1) VALUES (%2);").arg(keys.join(",")).arg(QString(":").append(keys.join(",:"))); } if (!executeQuery(&query,q1,bindValues,error,errorString)) { return false; } if (!update) { QLandmarkCategoryId id; id.setManagerUri(managerUri); id.setLocalId(query.lastInsertId().toString()); category->setCategoryId(id); } query.clear(); query.finish(); bindValues.clear(); bindValues.insert("catId",category->categoryId().localId()); QStringList attributeKeys = coreGenericCategoryAttributes; foreach(const QString &key, attributeKeys) { bindValues.clear(); bindValues.insert(":catId", category->categoryId().localId()); bindValues.insert(":key", key); bindValues.insert(":value", getCategoryAttribute(category,key)); if (!executeQuery(&query, "REPLACE INTO category_attribute(categoryId,key,value) VALUES(:catId,:key,:value)", bindValues,error,errorString)) { return false; } } *error = QLandmarkManager::NoError; *errorString = ""; return true; } bool DatabaseOperations::saveCategory(QLandmarkCategory *category, QLandmarkManager::Error *error, QString *errorString) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Save Category: unable to begin transaction, reason: %1").arg(db.lastError().text()); return false; } bool result = saveCategoryHelper(category, error, errorString); if (result) db.commit(); else db.rollback(); return result; } bool DatabaseOperations::saveCategories(QList * categories, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (errorMap) errorMap->clear(); QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Save Categories: unable to begin transaction, reason: %1").arg(db.lastError().text()); if (errorMap) { for (int i=0; i < categories->size(); ++i) errorMap->insert(i, *error); } return false; } bool noErrors = true; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString; QLandmarkManager::Error loopError; QString loopErrorString; bool result; for (int i = 0; i < categories->size(); ++i) { loopError = QLandmarkManager::NoError; loopErrorString = ""; if (queryRun && queryRun->isCanceled) { lastError = QLandmarkManager::CancelError; lastErrorString = "Category save was canceled"; if (errorMap) { for (int j = i; j < categories->size(); ++j) errorMap->insert(j, lastError); } noErrors = false; break; } QSqlQuery query(db); if (!query.exec("SAVEPOINT save")) { loopError = QLandmarkManager::UnknownError; loopErrorString = QString("Save categories: could not execute statement: %1\nReason:%2").arg(query.lastQuery()).arg(query.lastError().text()); result = false; } else { result = saveCategoryHelper(&(categories->operator [](i)), &loopError, &loopErrorString); } if (!result) { noErrors = false; lastError = loopError; lastErrorString = loopErrorString; if (errorMap) errorMap->insert(i, loopError); query.exec("ROLLBACK TO SAVEPOINT save"); } else { query.exec("RELEASE SAVEPOINT save"); } } db.commit(); if (noErrors) { if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } else { if (error) *error = lastError; if (errorString) *errorString = lastErrorString; } return noErrors; } bool DatabaseOperations::removeCategory(const QLandmarkCategoryId &categoryId, QLandmarkManager::Error *error, QString *errorString) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Remove category: unable to begin transaction, reason: %1").arg(db.lastError().text()); return false; } bool result = removeCategoryHelper(categoryId, error, errorString); if (result) db.commit(); else db.rollback(); return result; } bool DatabaseOperations::removeCategoryHelper(const QLandmarkCategoryId &categoryId, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (categoryId.managerUri() != managerUri) { if (error) *error = QLandmarkManager::CategoryDoesNotExistError; if (errorString) *errorString = "Category id comes from different landmark manager."; return false; } QSqlDatabase db = QSqlDatabase::database(connectionName); QMap bindValues; bindValues.insert("catId", categoryId.localId()); QString q0 = QString("SELECT 1 FROM category WHERE id = :catId"); QSqlQuery query(db); if(!executeQuery(&query,q0,bindValues,error,errorString)) { return false; } if (!query.next()) { *error = QLandmarkManager::CategoryDoesNotExistError; *errorString = QString("Category with local id %1, does not exist in database") .arg(categoryId.localId()); return false; } QStringList queryStrings; queryStrings << "DELETE FROM category WHERE id = :catId"; queryStrings << "DELETE FROM landmark_category WHERE categoryId = :catId"; queryStrings << "DELETE FROM category_attribute WHERE categoryId= :catId"; foreach(const QString &queryString, queryStrings) { if (!executeQuery(&query, queryString, bindValues, error,errorString)) { return false; } } *error = QLandmarkManager::NoError; *errorString = ""; return true; } bool DatabaseOperations::removeCategories(const QList &categoryIds, QMap *errorMap, QLandmarkManager::Error *error, QString *errorString) { Q_ASSERT(error); Q_ASSERT(errorString); if (errorMap) errorMap->clear(); QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Remove category: unable to begin transaction, reason: %1").arg(db.lastError().text()); if (errorMap) { for (int i=0; i < categoryIds.size(); ++i) errorMap->insert(i, *error); } return false; } bool noErrors = true; QLandmarkManager::Error lastError = QLandmarkManager::NoError; QString lastErrorString; QLandmarkManager::Error loopError; QString loopErrorString; bool result; for (int i = 0; i < categoryIds.size(); ++i) { loopError = QLandmarkManager::NoError; loopErrorString.clear(); if (queryRun && queryRun->isCanceled) { lastError = QLandmarkManager::CancelError; lastErrorString = "Category remove was canceled"; if (errorMap) { for (int j = i; j < categoryIds.size(); ++j) errorMap->insert(j, lastError); } noErrors = false; break; } QSqlQuery query(db); if (!query.exec("SAVEPOINT save")) { loopError = QLandmarkManager::UnknownError; loopErrorString = QString("Remove category: could not execute statement: %1\nReason:%2").arg(query.lastQuery()).arg(query.lastError().text()); result = false; } else { result = removeCategoryHelper(categoryIds.at(i), &loopError, &loopErrorString); } if (!result) { if (errorMap) errorMap->insert(i, loopError); noErrors = false; lastError = loopError; lastErrorString = loopErrorString; query.exec("ROLLBACK TO SAVEPOINT save"); } else { query.exec("RELEASE SAVEPOINT save"); } } db.commit(); if (noErrors) { if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } else { if (error) *error = lastError; if (errorString) *errorString = lastErrorString; } return noErrors; } bool DatabaseOperations::importLandmarks(QIODevice *device, const QString &format, QLandmarkManager::TransferOption option, const QLandmarkCategoryId &categoryId, QLandmarkManager::Error *error, QString *errorString, QueryRun *queryRun, QList *landmarkIds) { Q_ASSERT(error); Q_ASSERT(errorString); if (!device) { *error = QLandmarkManager::BadArgumentError; *errorString = "Invalid io device pointer"; return false; } QFile *file = qobject_cast(device); if (file) { if (!file->exists()) { *error = QLandmarkManager::DoesNotExistError; *errorString = QString("Import operation failed, file does not exist: %1").arg(file->fileName()); return false; } if (!file->open(QIODevice::ReadOnly)) { if (file->error() == QFile::OpenError) { *error = QLandmarkManager::PermissionsError; *errorString = QString("Insufficient permissions to open file"); return false; } else { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to open file for importing landmarks"); return false; } } } else if(!device->open(QIODevice::ReadOnly)) { *error = QLandmarkManager::UnknownError; *errorString = "Unable to open io device for importing landmarks"; return false; } QString detectedFormat = format; if (detectedFormat == "") { QXmlStreamReader reader(device); if (!reader.readNextStartElement()) { *error = QLandmarkManager::ParsingError; *errorString = "Could not read root element of io device"; device->reset(); return false; } else { if (reader.name() == "lmx") detectedFormat = (const QLatin1String)QLandmarkManager::Lmx; else if (reader.name() == "gpx") detectedFormat = (const QLatin1String)QLandmarkManager::Gpx; else { *error = QLandmarkManager::NotSupportedError; *errorString = "Unknown import file format"; device->reset(); return false; } } device->reset(); } bool result = false; if (detectedFormat == QLandmarkManager::Lmx) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Import operation failed, unable to begin transaction, reason: %1") .arg(db.lastError().text()); return false; } result = importLandmarksLmx(device, option, categoryId, error, errorString, queryRun, landmarkIds); if (result) db.commit(); else db.rollback(); device->close(); return result; } else if (detectedFormat == QLandmarkManager::Gpx) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.transaction()) { *error = QLandmarkManager::UnknownError; *errorString = QString("Import operation failed, unable to begin transaction, reason: %1") .arg(db.lastError().text()); return false; } result = importLandmarksGpx(device, option, categoryId, error, errorString, queryRun, landmarkIds); if (result) db.commit(); else db.rollback(); device->close(); return result; } else { if (error) *error = QLandmarkManager::NotSupportedError; if (errorString) *errorString = "The given format is not supported at this time"; device->close(); return false; } } bool DatabaseOperations::exportLandmarks( QIODevice *device, const QString &format, const QList &landmarkIds, QLandmarkManager::TransferOption option, QLandmarkManager::Error *error, QString *errorString) const { Q_ASSERT(error); Q_ASSERT(errorString); if (!device) { *error = QLandmarkManager::BadArgumentError; *errorString = "Invalid io device pointer"; return false; } QFile *file = qobject_cast(device); if (file) { if (!file->open(QIODevice::WriteOnly)) { if (file->error() == QFile::OpenError) { *error = QLandmarkManager::PermissionsError; *errorString = QString("Insufficient permissions to open file"); return false; } else { *error = QLandmarkManager::UnknownError; *errorString = QString("Unable to open file for importing landmarks"); return false; } } } else if (!device->open(QIODevice::WriteOnly)) { *error = QLandmarkManager::UnknownError; *errorString = "Unable to open io device for importing landmarks"; return false; } bool result = false; if (format == QLandmarkManager::Lmx) { result = exportLandmarksLmx(device, landmarkIds, option, error, errorString); device->close(); return result; } else if (format == QLandmarkManager::Gpx) { result = exportLandmarksGpx(device, landmarkIds, error, errorString); device->close(); return result; } else if (format =="") { *error = QLandmarkManager::BadArgumentError; *errorString = "No format provided"; device->close(); return false; } else { if (error) *error = QLandmarkManager::NotSupportedError; if (errorString) *errorString = "The given format is not supported at this time"; device->close(); return false; } } bool DatabaseOperations::importLandmarksLmx(QIODevice *device, QLandmarkManager::TransferOption option, const QLandmarkCategoryId &categoryId, QLandmarkManager::Error *error, QString *errorString, QueryRun *queryRun, QList *landmarkIds) { QLandmarkFileHandlerLmx lmxHandler(queryRun?&(queryRun->isCanceled):0); if (option == QLandmarkManager::AttachSingleCategory) { QLandmarkCategory singleCategory; singleCategory = category(categoryId,error,errorString); if (*error != QLandmarkManager::NoError) { return false; } } bool result = lmxHandler.importData(device); if (!result) { *error = lmxHandler.errorCode(); *errorString = lmxHandler.errorString(); return false; } QList landmarks = lmxHandler.landmarks(); QHash catIdLookup; QList landmarkCategoryNames; if (option == QLandmarkManager::IncludeCategoryData) { landmarkCategoryNames = lmxHandler.landmarkCategoryNames(); QList categories; categories = this->categories(QList(),QLandmarkNameSort(),-1, 0,error,errorString,true); if (*error != QLandmarkManager::NoError) { return false; } foreach(const QLandmarkCategory &category, categories) { catIdLookup.insert(category.name(), category.categoryId()); } } QStringList categoryNames; QList categoryIds; for (int i=0; i < landmarks.count(); ++i) { categoryIds.clear(); if (option == QLandmarkManager::IncludeCategoryData) { categoryNames = landmarkCategoryNames.at(i); foreach(const QString &name, categoryNames){ if (!catIdLookup.contains(name)) { QLandmarkCategory category; category.setName(name); saveCategoryHelper(&category,error,errorString); if (*error != QLandmarkManager::NoError) { if (landmarkIds) landmarkIds->clear(); return false; } catIdLookup.insert(category.name(), category.categoryId()); } categoryIds.append(catIdLookup.value(name)); } } else if (option == QLandmarkManager::AttachSingleCategory) { categoryIds.append(categoryId); } landmarks[i].setCategoryIds(categoryIds); if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Import of lmx file canceled"; } else { saveLandmarkHelper(&(landmarks[i]),error, errorString); } if (*error != QLandmarkManager::NoError) { if(landmarkIds) landmarkIds->clear(); return false; } if (landmarkIds) landmarkIds->append(landmarks[i].landmarkId()); } *error = QLandmarkManager::NoError; *errorString = ""; return true; } bool DatabaseOperations::importLandmarksGpx(QIODevice *device, QLandmarkManager::TransferOption option, const QLandmarkCategoryId &categoryId, QLandmarkManager::Error *error, QString *errorString, QueryRun *queryRun, QList *landmarkIds) { Q_ASSERT(error); Q_ASSERT(errorString); QLandmarkCategory category; if (option == QLandmarkManager::AttachSingleCategory) { category = this->category(categoryId, error, errorString); if ((*error) != QLandmarkManager::NoError) { return false; } } QLandmarkFileHandlerGpx gpxHandler(queryRun?&(queryRun->isCanceled):0); if (!gpxHandler.importData(device)) { *error = gpxHandler.error(); *errorString = gpxHandler.errorString(); return false; } QList landmarks = gpxHandler.waypoints(); for(int i =0; i < landmarks.count(); ++i) { if (option == QLandmarkManager::AttachSingleCategory) landmarks[i].addCategoryId(categoryId); if (queryRun && queryRun->isCanceled) { *error = QLandmarkManager::CancelError; *errorString = "Import of gpx file canceled"; } else { saveLandmarkHelper(&(landmarks[i]),error, errorString); } if (*error != QLandmarkManager::NoError) { if (landmarkIds) landmarkIds->clear(); return false; } if (landmarkIds) landmarkIds->append(landmarks[i].landmarkId()); } *error = QLandmarkManager::NoError; *errorString = ""; return true; } bool DatabaseOperations::exportLandmarksLmx(QIODevice *device, const QList &landmarkIds, QLandmarkManager::TransferOption option, QLandmarkManager::Error *error, QString *errorString) const { QLandmarkFileHandlerLmx lmxHandler(queryRun?&(queryRun->isCanceled):0); QLandmarkFilter filter; QList lms; if (landmarkIds.count() >0) lms = landmarks(landmarkIds, 0, error, errorString); else { QList sortOrders; lms = landmarks(filter, sortOrders, -1, 0, error, errorString); } if (*error != QLandmarkManager::NoError) return false; QList categories = this->categories(QList(),QLandmarkNameSort(),-1,0,error,errorString,true); if (*error != QLandmarkManager::NoError) { return false; } QHash categoryIdNameHash;//local id to name foreach(const QLandmarkCategory &category, categories) { categoryIdNameHash.insert(category.categoryId().localId(),category.name()); } lmxHandler.setTransferOption(option); lmxHandler.setLandmarks(lms); lmxHandler.setCategoryIdNameHash(categoryIdNameHash); bool result = lmxHandler.exportData(device); if (!result) { if (errorString) *error = lmxHandler.errorCode(); *errorString = lmxHandler.errorString(); } else { if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } return result; } bool DatabaseOperations::exportLandmarksGpx(QIODevice *device, const QList &landmarkIds, QLandmarkManager::Error *error, QString *errorString) const { QLandmarkFileHandlerGpx gpxHandler(queryRun?&(queryRun->isCanceled):0); QList sortOrders; QLandmarkFilter filter; QList lms; if (landmarkIds.count() > 0) { lms = landmarks(landmarkIds,0,error, errorString); gpxHandler.setBehavior(QLandmarkFileHandlerGpx::ExportAll); } else { lms = landmarks(filter, sortOrders, -1, 0, error, errorString); } if (error && *error != QLandmarkManager::NoError) return false; gpxHandler.setWaypoints(lms); bool result = gpxHandler.exportData(device); if (!result) { *error = gpxHandler.error(); *errorString = gpxHandler.errorString(); } else { if (error) *error = QLandmarkManager::NoError; if (errorString) *errorString = ""; } return result; } QLandmarkManager::SupportLevel DatabaseOperations::filterSupportLevel(const QLandmarkFilter &filter) const { switch(filter.type()) { case QLandmarkFilter::DefaultFilter: return QLandmarkManager::NativeSupport; case QLandmarkFilter::AttributeFilter: { const QLandmarkAttributeFilter attribFilter(filter); QStringList filterKeys = attribFilter.attributeKeys(); QStringList landmarkKeys; foreach(const QString key, filterKeys) { if (!supportedSearchableAttributes.contains(key)) return QLandmarkManager::NoSupport; } foreach (const QString &key, filterKeys) { if (attribFilter.matchFlags(key) & QLandmarkFilter::MatchCaseSensitive) return QLandmarkManager::NoSupport; } } case QLandmarkFilter::BoxFilter: { return QLandmarkManager::NativeSupport; } case QLandmarkFilter::CategoryFilter: { return QLandmarkManager::NativeSupport; } case QLandmarkFilter::IntersectionFilter: { const QLandmarkIntersectionFilter andFilter(filter); const QList& terms = andFilter.filters(); QLandmarkManager::SupportLevel currentLevel = QLandmarkManager::NativeSupport; if (terms.count() ==0) return currentLevel; for(int i=0; i < terms.count();i++) { if (filterSupportLevel(terms.at(i)) == QLandmarkManager::NoSupport) return QLandmarkManager::NoSupport; else if (filterSupportLevel(terms.at(i)) == QLandmarkManager::EmulatedSupport) currentLevel = QLandmarkManager::EmulatedSupport; } return currentLevel; } case QLandmarkFilter::LandmarkIdFilter: { return QLandmarkManager::NativeSupport; } case QLandmarkFilter::InvalidFilter: { return QLandmarkManager::NativeSupport; } case QLandmarkFilter::NameFilter: { const QLandmarkNameFilter nameFilter(filter); if (nameFilter.matchFlags() & QLandmarkFilter::MatchCaseSensitive) return QLandmarkManager::NoSupport; else return QLandmarkManager::NativeSupport; } case QLandmarkFilter::ProximityFilter: { return QLandmarkManager::NativeSupport; } case QLandmarkFilter::UnionFilter: { const QLandmarkUnionFilter orFilter(filter); const QList& terms = orFilter.filters(); QLandmarkManager::SupportLevel currentLevel = QLandmarkManager::NativeSupport; if (terms.count() == 0) return currentLevel; for (int i=0; i < terms.count(); i++) { if (filterSupportLevel(terms.at(i)) == QLandmarkManager::NoSupport) return QLandmarkManager::NoSupport; else if (filterSupportLevel(terms.at(i)) == QLandmarkManager::EmulatedSupport) currentLevel = QLandmarkManager::EmulatedSupport; } return currentLevel; } default: { return QLandmarkManager::NoSupport; } } return QLandmarkManager::NoSupport; } QLandmarkManager::SupportLevel DatabaseOperations::sortOrderSupportLevel(const QLandmarkSortOrder &sortOrder) const { QLandmarkManager::SupportLevel currentLevel = QLandmarkManager::NativeSupport; switch(sortOrder.type()) { case (QLandmarkSortOrder::NoSort): break; case (QLandmarkSortOrder::NameSort): { QLandmarkNameSort nameSort = sortOrder; if (nameSort.caseSensitivity() == Qt::CaseSensitive) currentLevel = QLandmarkManager::NoSupport; break; } default: currentLevel = QLandmarkManager::NoSupport; } return currentLevel; } QueryRun::QueryRun(QLandmarkAbstractRequest *req, const QString &uri, QLandmarkManagerEngineSqlite *eng, unsigned int runId) : request(req), error(QLandmarkManager::NoError), errorString(QString()), errorMap(QMap()), managerUri(uri), isCanceled(false), isDeleted(false), engine(eng), runId(runId) { }; QueryRun::~QueryRun() { } void QueryRun::run() { { connectionName = QUuid::createUuid().toString();//each connection needs a unique name QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName); db.setDatabaseName(engine->m_dbFilename); DatabaseOperations databaseOperations; databaseOperations.connectionName = connectionName; databaseOperations.managerUri = managerUri; databaseOperations.queryRun = this; QLandmarkAbstractRequest::RequestType requestType; QMutexLocker ml(&(engine->m_mutex)); if (engine->m_requestRunHash.contains(request)) { requestType = request->type(); } ml.unlock(); if (!db.open()) { qWarning() << db.lastError().text(); } error = QLandmarkManager::NoError; errorString =""; errorMap.clear(); switch(requestType){ case QLandmarkAbstractRequest::LandmarkIdFetchRequest: { QLandmarkIdFetchRequest *idFetchRequest; QList lmIds; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { idFetchRequest = static_cast(request); QLandmarkFilter filter = idFetchRequest->filter(); QList sorting = idFetchRequest->sorting(); int limit = idFetchRequest->limit(); int offset = idFetchRequest->offset(); ml.unlock(); lmIds = databaseOperations.landmarkIds(filter, sorting, limit, offset, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkIdFetchRequest", Qt::QueuedConnection, Q_ARG(QLandmarkIdFetchRequest *, idFetchRequest), Q_ARG(QList,lmIds), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::LandmarkFetchRequest: { QLandmarkFetchRequest *fetchRequest; QList lms; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { fetchRequest = static_cast(request); QLandmarkFilter filter = fetchRequest->filter(); QList sorting = fetchRequest->sorting(); int limit = fetchRequest->limit(); int offset = fetchRequest->offset(); ml.unlock(); lms = databaseOperations.landmarks(filter, sorting, limit, offset, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkFetchRequest", Qt::QueuedConnection, Q_ARG(QLandmarkFetchRequest *,fetchRequest), Q_ARG(QList,lms), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::LandmarkFetchByIdRequest : { QLandmarkFetchByIdRequest *byIdRequest; QList lms; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { byIdRequest = static_cast (request); QList lmIds= byIdRequest->landmarkIds(); ml.unlock(); lms = databaseOperations.landmarks(lmIds, &errorMap, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkFetchByIdRequest", Qt::QueuedConnection, Q_ARG(QLandmarkFetchByIdRequest *,byIdRequest), Q_ARG(QList,lms), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::LandmarkSaveRequest : { QLandmarkSaveRequest *saveRequest; QList lms; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { saveRequest = static_cast (request); lms = saveRequest->landmarks(); ml.unlock(); databaseOperations.saveLandmarks(&lms, &errorMap, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkSaveRequest", Qt::QueuedConnection, Q_ARG(QLandmarkSaveRequest *,saveRequest), Q_ARG(QList,lms), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::LandmarkRemoveRequest : { QLandmarkRemoveRequest *removeRequest; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { removeRequest= static_cast (request); QList lmIds = removeRequest->landmarkIds(); ml.unlock(); databaseOperations.removeLandmarks(lmIds, &errorMap, &error, &errorString); } ml.unlock(); } if (!isDeleted){ ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkRemoveRequest", Qt::QueuedConnection, Q_ARG(QLandmarkRemoveRequest *,removeRequest), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::CategoryIdFetchRequest : { QLandmarkCategoryIdFetchRequest *catIdFetchRequest; QList catIds; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { catIdFetchRequest = static_cast (request); QLandmarkNameSort nameSort = catIdFetchRequest->sorting(); int limit = catIdFetchRequest->limit(); int offset = catIdFetchRequest->offset(); ml.unlock(); catIds = databaseOperations.categoryIds(nameSort, limit, offset, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkCategoryIdFetchRequest", Qt::QueuedConnection, Q_ARG(QLandmarkCategoryIdFetchRequest *,catIdFetchRequest), Q_ARG(QList,catIds), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::CategoryFetchRequest : { QLandmarkCategoryFetchRequest *fetchRequest; QList cats; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { fetchRequest = static_cast (request); QList categoryIds; QLandmarkNameSort nameSort = fetchRequest->sorting(); int limit = fetchRequest->limit(); int offset = fetchRequest->offset(); bool needAll = true; ml.unlock(); cats =databaseOperations.categories(categoryIds, nameSort, limit, offset, &error, &errorString, needAll); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkCategoryFetchRequest", Q_ARG(QLandmarkCategoryFetchRequest *,fetchRequest), Q_ARG(QList,cats), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::CategoryFetchByIdRequest : { QLandmarkCategoryFetchByIdRequest *byIdRequest; QList categories; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { byIdRequest = static_cast (request); QList categoryIds = byIdRequest->categoryIds(); ml.unlock(); categories = databaseOperations.categories(categoryIds,&errorMap, &error, &errorString); } ml.unlock(); } if (this->isCanceled) { categories.clear(); error = QLandmarkManager::CancelError; errorString = "Category save request was canceled"; } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkCategoryFetchByIdRequest", Q_ARG(QLandmarkCategoryFetchByIdRequest *,byIdRequest), Q_ARG(QList, categories), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::CategorySaveRequest : { QLandmarkCategorySaveRequest *saveRequest; QList categories; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { saveRequest = static_cast (request); categories = saveRequest->categories(); ml.unlock(); databaseOperations.saveCategories( &categories, &errorMap, &error, &errorString); } ml.unlock(); } if (this->isCanceled) { categories.clear(); error = QLandmarkManager::CancelError; errorString = "Category save request was canceled"; } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkCategorySaveRequest", Q_ARG(QLandmarkCategorySaveRequest *,saveRequest), Q_ARG(QList,categories), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::CategoryRemoveRequest : { QLandmarkCategoryRemoveRequest *removeRequest; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { removeRequest = static_cast (request); QList categoryIds = removeRequest->categoryIds(); ml.unlock(); databaseOperations.removeCategories(categoryIds, &errorMap, &error, &errorString); } ml.unlock(); } if (this->isCanceled) { error = QLandmarkManager::CancelError; errorString = "Category remove request was canceled"; } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkCategoryRemoveRequest", Q_ARG(QLandmarkCategoryRemoveRequest *,removeRequest), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(ERROR_MAP, errorMap), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::ImportRequest : { QLandmarkImportRequest *importRequest; QList landmarkIds; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { importRequest = static_cast (request); QIODevice *device = importRequest->device(); QString format = importRequest->format(); QLandmarkManager::TransferOption transferOption = importRequest->transferOption(); QLandmarkCategoryId categoryId = importRequest->categoryId(); ml.unlock(); databaseOperations.importLandmarks(device, format, transferOption, categoryId, &error, &errorString, this, &landmarkIds); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkImportRequest", Q_ARG(QLandmarkImportRequest *, importRequest), Q_ARG(QList, landmarkIds), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } case QLandmarkAbstractRequest::ExportRequest : { QLandmarkExportRequest *exportRequest; if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) { exportRequest = static_cast (request); QIODevice *device = exportRequest->device(); QString format = exportRequest->format(); QList landmarkIds = exportRequest->landmarkIds(); QLandmarkManager::TransferOption transferOption = exportRequest->transferOption(); ml.unlock(); databaseOperations.exportLandmarks(device, format, landmarkIds, transferOption, &error, &errorString); } ml.unlock(); } if (!isDeleted) { ml.relock(); if (engine->m_requestRunHash.contains(request)) engine->m_requestRunHash.remove(request); ml.unlock(); QMetaObject::invokeMethod(engine, "updateLandmarkExportRequest", Q_ARG(QLandmarkExportRequest *, exportRequest), Q_ARG(QLandmarkManager::Error, error), Q_ARG(QString, errorString), Q_ARG(QLandmarkAbstractRequest::State,QLandmarkAbstractRequest::FinishedState), Q_ARG(unsigned int, runId)); } break; } default: break; } db.close(); } QSqlDatabase::removeDatabase(connectionName); } const QStringList DatabaseOperations::coreAttributes = QStringList() << "name" << "latitude" << "longitude" << "altitude"; const QStringList DatabaseOperations::coreGenericAttributes = QStringList() << "description" << "iconUrl" << "radius" << "countryCode" << "country" << "state" << "county" << "city" << "district" << "street" << "postcode" << "phoneNumber" << "url"; const QStringList DatabaseOperations::supportedSearchableAttributes = QStringList() << "name" << "description" << "countryCode" << "country" << "state" << "county" << "city" << "district" << "street" << "postcode" << "phoneNumber"; const QStringList DatabaseOperations::coreCategoryAttributes = QStringList() << "name"; const QStringList DatabaseOperations::coreGenericCategoryAttributes = QStringList() << "iconUrl";