void GosmoreRunner::reverseGeocoding( const GeoDataCoordinates &coordinates )
{
    if ( !d->m_gosmoreMapFile.exists() )
    {
        emit reverseGeocodingFinished( coordinates, GeoDataPlacemark() );
        return;
    }

    QString queryString = "flat=%1&flon=%2&tlat=%1&tlon=%2&fastest=1&v=motorcar";
    double lon = coordinates.longitude( GeoDataCoordinates::Degree );
    double lat = coordinates.latitude( GeoDataCoordinates::Degree );
    queryString = queryString.arg( lat, 0, 'f', 8).arg(lon, 0, 'f', 8 );
    QByteArray output = d->retrieveWaypoints( queryString );

    GeoDataPlacemark placemark;
    placemark.setCoordinate( coordinates );

    QStringList lines = QString::fromUtf8( output ).split( '\r' );
    if ( lines.size() > 2 ) {
        QStringList fields = lines.at( lines.size()-2 ).split(',');
        if ( fields.size() >= 5 ) {
            QString road = fields.last().trimmed();
            placemark.setAddress( road );
            GeoDataExtendedData extendedData;
            extendedData.addValue( GeoDataData( "road", road ) );
            placemark.setExtendedData( extendedData );
        }
    }

    emit reverseGeocodingFinished( coordinates, placemark );
}
Ejemplo n.º 2
0
void HostipRunner::slotRequestFinished( QNetworkReply* reply )
{
    double lon(0.0), lat(0.0);
    for ( QString line = reply->readLine(); !line.isEmpty(); line = reply->readLine() ) {
        QString lonInd = "Longitude: ";
        if ( line.startsWith(lonInd) ) {
            lon = line.mid( lonInd.length() ).toDouble();
        }

        QString latInd = "Latitude: ";
        if (line.startsWith( latInd) ) {
            lat = line.mid( latInd.length() ).toDouble();
        }
    }

    QVector<GeoDataPlacemark*> placemarks;

    if (lon != 0.0 && lat != 0.0) {
        GeoDataPlacemark *placemark = new GeoDataPlacemark;

        placemark->setName( m_hostInfo.hostName() );

        QString description("%1 (%2)");
        placemark->setDescription( description.
                                 arg( m_hostInfo.hostName() ).
                                 arg( m_hostInfo.addresses().first().toString() ) );

        placemark->setCoordinate( lon * DEG2RAD, lat * DEG2RAD );
        placemark->setVisualCategory( GeoDataFeature::Coordinate );
        placemarks << placemark;
    }
    
    emit searchFinished( placemarks );
}
Ejemplo n.º 3
0
void OsmNode::create(GeoDataDocument *document) const
{
    GeoDataFeature::GeoDataVisualCategory const category = OsmPresetLibrary::determineVisualCategory(m_osmData);
    if (category == GeoDataFeature::None ||
       (category >= GeoDataFeature::HighwaySteps && category <= GeoDataFeature::HighwayMotorway)) {
        return;
    }

    GeoDataPlacemark* placemark = new GeoDataPlacemark;
    placemark->setOsmData(m_osmData);
    placemark->setCoordinate(m_coordinates);

    if ((category == GeoDataFeature::TransportCarShare || category == GeoDataFeature::MoneyAtm)
            && m_osmData.containsTagKey("operator")) {
        placemark->setName(m_osmData.tagValue("operator"));
    } else {
        placemark->setName(m_osmData.tagValue("name"));
    }
    placemark->setZoomLevel( 18 );
    placemark->setVisualCategory(category);
    placemark->setStyle( 0 );

    if (category == GeoDataFeature::NaturalTree) {
        qreal const lat = m_coordinates.latitude(GeoDataCoordinates::Degree);
        if (qAbs(lat) > 15) {
            /** @todo Should maybe auto-adjust to MarbleClock at some point */
            QDate const date = QDate::currentDate();
            bool const southernHemisphere = lat < 0;
            QDate const autumnStart = QDate(date.year(), southernHemisphere ? 3 : 9, 15);
            QDate const winterEnd = southernHemisphere ? QDate(date.year(), 8, 15) : QDate(date.year()+1, 2, 15);
            if (date > autumnStart && date < winterEnd) {
                QDate const autumnEnd = QDate(date.year(), southernHemisphere ? 5 : 11, 15);
                QString const season = date < autumnEnd ? "autumn" : "winter";
                GeoDataIconStyle iconStyle = placemark->style()->iconStyle();
                QString const bitmap = QString("bitmaps/osmcarto/symbols/48/individual/tree-29-%1.png").arg(season);
                iconStyle.setIconPath(MarbleDirs::path(bitmap));

                GeoDataStyle* style = new GeoDataStyle(*placemark->style());
                style->setIconStyle(iconStyle);
                placemark->setStyle(style);

            }
        }
    }

    OsmObjectManager::registerId(m_osmData.id());
    document->append(placemark);
}
Ejemplo n.º 4
0
void TourWidgetPrivate::addPlacemark()
{
    // Get the normalized coordinates of the focus point. There will be automatically added a new
    // placemark.
    qreal lat = m_widget->focusPoint().latitude();
    qreal lon = m_widget->focusPoint().longitude();
    GeoDataCoordinates::normalizeLonLat( lon, lat );

    GeoDataDocument *document = new GeoDataDocument;
    if( m_document->id().isEmpty() ) {
        if( m_document->name().isEmpty() ) {
            m_document->setId( "untitled_tour" );
        } else {
            m_document->setId( m_document->name().trimmed().replace( " ", "_" ).toLower() );
        }
    }
    document->setTargetId( m_document->id() );

    GeoDataPlacemark *placemark = new GeoDataPlacemark;
    placemark->setCoordinate( lon, lat );
    placemark->setVisible( true );
    placemark->setBalloonVisible( true );
    GeoDataStyle *newStyle = new GeoDataStyle( *placemark->style() );
    newStyle->iconStyle().setIcon( QImage() );
    newStyle->iconStyle().setIconPath( MarbleDirs::path("bitmaps/redflag_22.png") );
    placemark->setStyle( newStyle );

    document->append( placemark );

    GeoDataCreate *create = new GeoDataCreate;
    create->append( document );
    GeoDataUpdate *update = new GeoDataUpdate;
    update->setCreate( create );
    GeoDataAnimatedUpdate *animatedUpdate = new GeoDataAnimatedUpdate;
    animatedUpdate->setUpdate( update );

    if( m_delegate->editAnimatedUpdate( animatedUpdate ) ) {
        addTourPrimitive( animatedUpdate );
        m_delegate->setDefaultFeatureId( placemark->id() );
    } else {
        delete animatedUpdate;
    }
}
Ejemplo n.º 5
0
void OsmNominatimRunner::handleReverseGeocodingResult( QNetworkReply* reply )
{
    if ( !reply->bytesAvailable() ) {
        returnNoReverseGeocodingResult();
        return;
    }

    QDomDocument xml;
    if ( !xml.setContent( reply->readAll() ) ) {
        mDebug() << "Cannot parse osm nominatim result " << xml.toString();
        returnNoReverseGeocodingResult();
        return;
    }

    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName( "result" );
    if ( places.size() == 1 ) {
        QString address = places.item( 0 ).toElement().text();
        GeoDataPlacemark placemark;
        placemark.setAddress( address );
        placemark.setCoordinate( GeoDataPoint( m_coordinates ) );

        QDomNodeList details = root.elementsByTagName( "addressparts" );
        if ( details.size() == 1 ) {
            GeoDataExtendedData extendedData;
            addData( details, "road", &extendedData );
            addData( details, "house_number", &extendedData );
            addData( details, "village", &extendedData );
            addData( details, "city", &extendedData );
            addData( details, "county", &extendedData );
            addData( details, "state", &extendedData );
            addData( details, "postcode", &extendedData );
            addData( details, "country", &extendedData );
            placemark.setExtendedData( extendedData );
        }

        emit reverseGeocodingFinished( m_coordinates, placemark );
    } else {
        returnNoReverseGeocodingResult();
    }
}
Ejemplo n.º 6
0
void GeoUriRunner::search(const QString &searchTerm, const GeoDataLatLonBox &)
{
    QVector<GeoDataPlacemark*> vector;

    GeoUriParser uriParser(searchTerm);
    const bool success = uriParser.parse();
    if (success &&
        (uriParser.planet().id() == model()->planet()->id())) {
        const GeoDataCoordinates coordinates = uriParser.coordinates();

        GeoDataPlacemark *placemark = new GeoDataPlacemark;
        placemark->setName(searchTerm);
        placemark->setCoordinate(coordinates);
        placemark->setVisualCategory(GeoDataPlacemark::Coordinate);
        placemark->setPopularity(1000000000);
        placemark->setZoomLevel(1);

        vector.append(placemark);
    }

    emit searchFinished(vector);
}
Ejemplo n.º 7
0
void OsmNominatimRunner::handleResult( QNetworkReply* reply )
{   
    QDomDocument xml;
    if (!xml.setContent(reply->readAll())) {
        qWarning() << "Cannot parse osm nominatim result";
        returnNoResults();
        return;
    }

    QVector<GeoDataPlacemark*> placemarks;
    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName("place");
    for (int i=0; i<places.size(); ++i) {
        QDomNode place = places.at(i);
        QDomNamedNodeMap attributes = place.attributes();
        QString lon = attributes.namedItem("lon").nodeValue();
        QString lat = attributes.namedItem("lat").nodeValue();
        QString desc = attributes.namedItem("display_name").nodeValue();
        QString key = attributes.namedItem("class").nodeValue();
        QString value = attributes.namedItem("type").nodeValue();

        QString name = place.firstChildElement(value).text();
        QString road = place.firstChildElement("road").text();

        QString city = place.firstChildElement("city").text();
        if( city.isEmpty() ) {
            city = place.firstChildElement("town").text();
            if( city.isEmpty() ) {
                city = place.firstChildElement("village").text();
            } if( city.isEmpty() ) {
                city = place.firstChildElement("hamlet").text();
            }
        }

        QString administrative = place.firstChildElement("county").text();
        if( administrative.isEmpty() ) {
            administrative = place.firstChildElement("region").text();
            if( administrative.isEmpty() ) {
                administrative = place.firstChildElement("state").text();
            }
        }

        QString country = place.firstChildElement("country").text();

        QString description;
        for (int i=0; i<place.childNodes().size(); ++i) {
            QDomElement item = place.childNodes().at(i).toElement();
            description += item.nodeName() + ':' + item.text() + '\n';
        }
        description += "Category: " + key + '/' + value;

        if (!lon.isEmpty() && !lat.isEmpty() && !desc.isEmpty()) {
            QString placemarkName;
            GeoDataPlacemark* placemark = new GeoDataPlacemark;
            // try to provide 2 fields
            if (!name.isEmpty()) {
                placemarkName = name;
            }
            if (!road.isEmpty() && road != placemarkName ) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += ", ";
                }
                placemarkName += road;
            }
            if (!city.isEmpty() && !placemarkName.contains(",") && city != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += ", ";
                }
                placemarkName += city;
            }
            if (!administrative.isEmpty()&& !placemarkName.contains(",") && administrative != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += ", ";
                }
                placemarkName += administrative;
            }
            if (!country.isEmpty()&& !placemarkName.contains(",") && country != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += ", ";
                }
                placemarkName += country;
            }
            if (placemarkName.isEmpty()) {
                placemarkName = desc;
            }
            placemark->setName( placemarkName );
            placemark->setDescription(description);
            placemark->setCoordinate( lon.toDouble(), lat.toDouble(), 0, GeoDataCoordinates::Degree );
            GeoDataFeature::GeoDataVisualCategory category = GeoDataFeature::OsmVisualCategory( key + '=' + value );
            placemark->setVisualCategory( category );
            placemarks << placemark;
        }
    }
    
    emit searchFinished( placemarks );
}
Ejemplo n.º 8
0
void OsmNode::create(GeoDataDocument *document) const
{
    GeoDataFeature::GeoDataVisualCategory const category = OsmPresetLibrary::determineVisualCategory(m_osmData);
    if (category == GeoDataFeature::None ||
       (category >= GeoDataFeature::HighwaySteps && category <= GeoDataFeature::HighwayMotorway)) {
        return;
    }

    GeoDataPlacemark* placemark = new GeoDataPlacemark;
    placemark->setOsmData(m_osmData);
    placemark->setCoordinate(m_coordinates);

    if ((category == GeoDataFeature::TransportCarShare || category == GeoDataFeature::MoneyAtm)
            && m_osmData.containsTagKey("operator")) {
        placemark->setName(m_osmData.tagValue("operator"));
    } else {
        placemark->setName(m_osmData.tagValue("name"));
    }
    placemark->setVisualCategory(category);
    placemark->setStyle( GeoDataStyle::Ptr() );

    if (category == GeoDataFeature::NaturalTree) {
        qreal const lat = m_coordinates.latitude(GeoDataCoordinates::Degree);
        if (qAbs(lat) > 15) {
            /** @todo Should maybe auto-adjust to MarbleClock at some point */
            QDate const date = QDate::currentDate();
            bool const southernHemisphere = lat < 0;
            QDate const autumnStart = QDate(date.year(), southernHemisphere ? 3 : 9, 15);
            QDate const winterEnd = southernHemisphere ? QDate(date.year(), 8, 15) : QDate(date.year()+1, 2, 15);
            if (date > autumnStart && date < winterEnd) {
                QDate const autumnEnd = QDate(date.year(), southernHemisphere ? 5 : 11, 15);
                QString const season = date < autumnEnd ? "autumn" : "winter";
                GeoDataIconStyle iconStyle = placemark->style()->iconStyle();
                QString const bitmap = QString("bitmaps/osmcarto/symbols/48/individual/tree-29-%1.png").arg(season);
                iconStyle.setIconPath(MarbleDirs::path(bitmap));

                GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
                style->setIconStyle(iconStyle);
                placemark->setStyle(style);

            }
        }
    }

    placemark->setZoomLevel( 18 );
    if (category >= GeoDataFeature::PlaceCity && category <= GeoDataFeature::PlaceVillage) {
        int const population = m_osmData.tagValue("population").toInt();
        placemark->setPopulation(qMax(0, population));
        if (population > 0) {
            placemark->setZoomLevel(populationIndex(population));
            placemark->setPopularity(population);
        } else {
            switch (category) {
            case GeoDataFeature::PlaceCity:     placemark->setZoomLevel(9);  break;
            case GeoDataFeature::PlaceSuburb:   placemark->setZoomLevel(13);  break;
            case GeoDataFeature::PlaceHamlet:   placemark->setZoomLevel(15);  break;
            case GeoDataFeature::PlaceLocality: placemark->setZoomLevel(15);  break;
            case GeoDataFeature::PlaceTown:     placemark->setZoomLevel(11);  break;
            case GeoDataFeature::PlaceVillage:  placemark->setZoomLevel(13); break;
            default:                            placemark->setZoomLevel(10); break;
            }
        }
    } else if (category == GeoDataFeature::NaturalPeak) {
        placemark->setZoomLevel(11);
        bool isInteger = false;
        int const elevation = m_osmData.tagValue("ele").toInt(&isInteger);
        if (isInteger) {
            placemark->setName(QString("%1 (%2 m)").arg(placemark->name()).arg(elevation));
        }
    }

    OsmObjectManager::registerId(m_osmData.id());
    document->append(placemark);
}
Ejemplo n.º 9
0
GeoDataDocument* OpenRouteServiceRunner::parse( const QByteArray &content ) const
{
    QDomDocument xml;
    if ( !xml.setContent( content ) ) {
        mDebug() << "Cannot parse xml file with routing instructions.";
        return nullptr;
    }

    QDomElement root = xml.documentElement();

    GeoDataDocument* result = new GeoDataDocument();
    result->setName(QStringLiteral("OpenRouteService"));

    QDomNodeList errors = root.elementsByTagName(QStringLiteral("xls:Error"));
    if ( errors.size() > 0 ) {
        return nullptr;
        // Returning early because fallback routing providers are used now
        // The code below can be used to parse OpenGis errors reported by ORS
        // and may be useful in the future

        for (int i=0 ; i < errors.length(); ++i ) {
            QDomNode node = errors.item( i );
            QString errorMessage = node.attributes().namedItem(QStringLiteral("message")).nodeValue();
            QRegExp regexp = QRegExp( "^(.*) Please Check your Position: (-?[0-9]+.[0-9]+) (-?[0-9]+.[0-9]+) !" );
            if ( regexp.indexIn( errorMessage ) == 0 ) {
                if ( regexp.capturedTexts().size() == 4 ) {
                    GeoDataPlacemark* placemark = new GeoDataPlacemark;
                    placemark->setName( regexp.capturedTexts().at( 1 ) );
                    GeoDataCoordinates position;
                    position.setLongitude( regexp.capturedTexts().at( 2 ).toDouble(), GeoDataCoordinates::Degree );
                    position.setLatitude( regexp.capturedTexts().at( 3 ).toDouble(), GeoDataCoordinates::Degree );
                    placemark->setCoordinate( position );
                    result->append( placemark );
                }
            } else {
                mDebug() << "Error message " << errorMessage << " not parsable.";
                /** @todo: How to handle this now with plugins? */
//                QString message = tr( "Sorry, a problem occurred when calculating the route. Try adjusting start and destination points." );
//                QPointer<QMessageBox> messageBox = new QMessageBox( QMessageBox::Warning, "Route Error", message );
//                messageBox->setDetailedText( errorMessage );
//                messageBox->exec();
//                delete messageBox;
            }
        }
    }

    GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
    routePlacemark->setName(QStringLiteral("Route"));
    QTime time;
    QDomNodeList summary = root.elementsByTagName(QStringLiteral("xls:RouteSummary"));
    if ( summary.size() > 0 ) {
        QDomNodeList timeNodeList = summary.item(0).toElement().elementsByTagName(QStringLiteral("xls:TotalTime"));
        if ( timeNodeList.size() == 1 ) {
            QRegExp regexp = QRegExp( "^P(?:(\\d+)D)?T(?:(\\d+)H)?(?:(\\d+)M)?(\\d+)S" );
            if ( regexp.indexIn( timeNodeList.item( 0 ).toElement().text() ) == 0 ) {
                QStringList matches = regexp.capturedTexts();
                unsigned int hours( 0 ), minutes( 0 ), seconds( 0 );
                switch ( matches.size() ) {
                case 5:
                    // days    = regexp.cap( matches.size() - 4 ).toInt();
                    // Intentionally no break
                case 4:
                    hours   = regexp.cap( matches.size() - 3 ).toInt();
                    // Intentionally no break
                case 3:
                    minutes = regexp.cap( matches.size() - 2 ).toInt();
                    // Intentionally no break
                case 2:
                    seconds = regexp.cap( matches.size() - 1 ).toInt();
                    break;
                default:
                    mDebug() << "Unable to parse time string " << timeNodeList.item( 0 ).toElement().text();
                }

                time = QTime( hours, minutes, seconds, 0 );
            }
        }
    }

    GeoDataLineString* routeWaypoints = new GeoDataLineString;
    QDomNodeList geometry = root.elementsByTagName(QStringLiteral("xls:RouteGeometry"));
    if ( geometry.size() > 0 ) {
        QDomNodeList waypoints = geometry.item( 0 ).toElement().elementsByTagName( "gml:pos" );
        for (int i=0 ; i < waypoints.length(); ++i ) {
            QDomNode node = waypoints.item( i );
            const QStringList content = node.toElement().text().split(QLatin1Char(' '));
            if ( content.length() == 2 ) {
                GeoDataCoordinates position;
                position.setLongitude( content.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
                position.setLatitude( content.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
                routeWaypoints->append( position );
            }
        }
    }
    routePlacemark->setGeometry( routeWaypoints );

    qreal length = routeWaypoints->length( EARTH_RADIUS );
    const QString name = nameString( "ORS", length, time );
    const GeoDataExtendedData data = routeData( length, time );
    routePlacemark->setExtendedData( data );
    result->setName( name );

    result->append( routePlacemark );

    QDomNodeList instructionList = root.elementsByTagName(QStringLiteral("xls:RouteInstructionsList"));
    if ( instructionList.size() > 0 ) {
        QDomNodeList instructions = instructionList.item(0).toElement().elementsByTagName(QStringLiteral("xls:RouteInstruction"));
        for (int i=0 ; i < instructions.length(); ++i ) {
            QDomElement node = instructions.item( i ).toElement();

            QDomNodeList textNodes = node.elementsByTagName(QStringLiteral("xls:Instruction"));
            QDomNodeList positions = node.elementsByTagName(QStringLiteral("gml:pos"));

            if ( textNodes.size() > 0 && positions.size() > 0 ) {
                const QStringList content = positions.at(0).toElement().text().split(QLatin1Char(' '));
                if ( content.length() == 2 ) {
                    GeoDataLineString *lineString = new GeoDataLineString;

                    for( int i = 0; i < positions.count(); ++i ) {
                         const QStringList pointList = positions.at(i).toElement().text().split(QLatin1Char(' '));
                         GeoDataCoordinates position;
                         position.setLongitude( pointList.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
                         position.setLatitude( pointList.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
                         lineString->append( position );
                    }

                    GeoDataPlacemark* instruction = new GeoDataPlacemark;

                    QString const text = textNodes.item( 0 ).toElement().text().remove(QRegExp("<[^>]*>"));
                    GeoDataExtendedData extendedData;
                    GeoDataData turnTypeData;
                    turnTypeData.setName(QStringLiteral("turnType"));
                    QString road;
                    RoutingInstruction::TurnType turnType = parseTurnType( text, &road );
                    turnTypeData.setValue( turnType );
                    extendedData.addValue( turnTypeData );
                    if ( !road.isEmpty() ) {
                        GeoDataData roadName;
                        roadName.setName(QStringLiteral("roadName"));
                        roadName.setValue( road );
                        extendedData.addValue( roadName );
                    }

                    QString const instructionText = turnType == RoutingInstruction::Unknown ? text : RoutingInstruction::generateRoadInstruction( turnType, road );
                    instruction->setName( instructionText );
                    instruction->setExtendedData( extendedData );
                    instruction->setGeometry( lineString );
                    result->append( instruction );
                }
            }
        }
    }

    return result;
}
Ejemplo n.º 10
0
void OsmNominatimRunner::handleResult( QNetworkReply* reply )
{   
    QDomDocument xml;
    if (!xml.setContent(reply->readAll())) {
        qWarning() << "Cannot parse osm nominatim result";
        qWarning() << reply->error();
        returnNoResults();
        return;
    }

    QVector<GeoDataPlacemark*> placemarks;
    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName(QStringLiteral("place"));
    for (int i=0; i<places.size(); ++i) {
        QDomNode place = places.at(i);
        QDomNamedNodeMap attributes = place.attributes();
        QString lon = attributes.namedItem(QStringLiteral("lon")).nodeValue();
        QString lat = attributes.namedItem(QStringLiteral("lat")).nodeValue();
        QString desc = attributes.namedItem(QStringLiteral("display_name")).nodeValue();
        QString key = attributes.namedItem(QStringLiteral("class")).nodeValue();
        QString value = attributes.namedItem(QStringLiteral("type")).nodeValue();

        OsmPlacemarkData data;

        GeoDataExtendedData placemarkData = extractChildren(place);
        placemarkData.addValue(GeoDataData(QStringLiteral("class"), key));
        placemarkData.addValue(GeoDataData(QStringLiteral("type"), value));

        QString name = place.firstChildElement(value).text();
        QString road = place.firstChildElement(QStringLiteral("road")).text();
        placemarkData.addValue(GeoDataData(QStringLiteral("name"), name));

        QString city = place.firstChildElement(QStringLiteral("city")).text();
        if( city.isEmpty() ) {
            city = place.firstChildElement(QStringLiteral("town")).text();
            if( city.isEmpty() ) {
                city = place.firstChildElement(QStringLiteral("village")).text();
            } if( city.isEmpty() ) {
                city = place.firstChildElement(QStringLiteral("hamlet")).text();
            }
        }

        QString administrative = place.firstChildElement(QStringLiteral("county")).text();
        if( administrative.isEmpty() ) {
            administrative = place.firstChildElement(QStringLiteral("region")).text();
            if( administrative.isEmpty() ) {
                administrative = place.firstChildElement(QStringLiteral("state")).text();
                data.addTag(QStringLiteral("addr:state"), administrative);
            } else {
                data.addTag(QStringLiteral("district"), administrative);
            }
        }

        QString country = place.firstChildElement(QStringLiteral("country")).text();

        QString description;
        for (int i=0; i<place.childNodes().size(); ++i) {
            QDomElement item = place.childNodes().at(i).toElement();
            description += item.nodeName() + QLatin1Char(':') + item.text() + QLatin1Char('\n');
        }
        description += QLatin1String("Category: ") + key + QLatin1Char('/') + value;

        if (!lon.isEmpty() && !lat.isEmpty() && !desc.isEmpty()) {
            QString placemarkName;
            GeoDataPlacemark* placemark = new GeoDataPlacemark;
            // try to provide 2 fields
            if (!name.isEmpty()) {
                placemarkName = name;
            }
            if (!road.isEmpty() && road != placemarkName ) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += QLatin1String(", ");
                }
                placemarkName += road;
                data.addTag(QStringLiteral("addr:street"), road);
            }
            if (!city.isEmpty() && !placemarkName.contains(QLatin1Char(',')) && city != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += QLatin1String(", ");
                }
                placemarkName += city;
                data.addTag(QStringLiteral("addr:city"), city);
            }
            if (!administrative.isEmpty() && !placemarkName.contains(QLatin1Char(',')) && administrative != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += QLatin1String(", ");
                }
                placemarkName += administrative;
            }
            if (!country.isEmpty() && !placemarkName.contains(QLatin1Char(',')) && country != placemarkName) {
                if( !placemarkName.isEmpty() ) {
                    placemarkName += QLatin1String(", ");
                }
                placemarkName += country;
                data.addTag(QStringLiteral("addr:country"), country);
            }
            if (placemarkName.isEmpty()) {
                placemarkName = desc;
            }
            placemark->setName( placemarkName );
            placemark->setDescription(description);
            placemark->setAddress(desc);
            placemark->setCoordinate( lon.toDouble(), lat.toDouble(), 0, GeoDataCoordinates::Degree );
            const auto category = StyleBuilder::determineVisualCategory(data);
            placemark->setVisualCategory( category );
            placemark->setExtendedData(placemarkData);
            placemark->setOsmData(data);
            placemarks << placemark;
        }
    }
    
    emit searchFinished( placemarks );
}