File indexing completed on 2025-01-05 03:59:23

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2015 Marius-Valeriu Stanciu <stanciumarius94@gmail.com>
0004 //
0005 
0006 #ifndef MARBLE_OSMPLACEMARKDATA_H
0007 #define MARBLE_OSMPLACEMARKDATA_H
0008 
0009 // Qt
0010 #include <QHash>
0011 #include <QMetaType>
0012 #include <QString>
0013 #include <QScopedPointer>
0014 #include <QSharedPointer>
0015 
0016 
0017 // Marble
0018 #include "GeoDataCoordinates.h"
0019 #include "GeoDocument.h"
0020 #include "digikam_export.h"
0021 
0022 class QXmlStreamAttributes;
0023 
0024 namespace Marble
0025 {
0026 
0027 /** Type of OSM element. */
0028 enum class OsmType {
0029     Node,
0030     Way,
0031     Relation
0032 };
0033 
0034 /** Identifier for an OSM element.
0035  *  @note OSM uses distinct id spaces for all its three basic element types, so just the numeric id
0036  *  on its own doesn't identify an element without knowing its type.
0037  */
0038 struct OsmIdentifier {
0039     inline OsmIdentifier() = default;
0040     inline OsmIdentifier(qint64 _id, OsmType _type) : id(_id), type(_type) {}
0041 
0042     qint64 id = 0;
0043     OsmType type = OsmType::Way;
0044 
0045     inline bool operator==(OsmIdentifier other) const { return id == other.id && type == other.type; }
0046 };
0047 
0048 /** Forward declaration */
0049 class OsmPlacemarkDataHashRef;
0050 
0051 /**
0052  * This class is used to encapsulate the osm data fields kept within a placemark's extendedData.
0053  * It stores OSM server generated data: id, version, changeset, uid, visible, user, timestamp;
0054  * It also stores a hash map of \<tags\> ( key-value mappings ) and a hash map of component osm
0055  * placemarks @see m_nodeReferences @see m_memberReferences
0056  *
0057  * The usual workflow with osmData goes as follows:
0058  *
0059  * Parsing stage:
0060  * The OsmParser parses tags (they have server-generated attributes), creates new placemarks and
0061  * assigns them new OsmPlacemarkData objects with all the needed information.
0062  *
0063  * Editing stage:
0064  * While editing placemarks that have OsmPlacemarkData, all relevant changes reflect on the
0065  * OsmPlacemarkData object as well, so as not to uncorrelate data from the actual placemarks.
0066  *
0067  * Writing stage:
0068  * The OsmObjectManager assigns OsmPlacemarkData objects to placemarks that do not have it
0069  * ( these are usually newly created placemarks within the editor, or placemarks loaded from
0070  * ".kml" files ). Placemarks that already have it, are simply written as-is.
0071  */
0072 class DIGIKAM_EXPORT OsmPlacemarkData: public GeoNode
0073 {
0074 
0075 public:
0076 
0077     OsmPlacemarkData();
0078     virtual ~OsmPlacemarkData();
0079 
0080     qint64 id() const;
0081     qint64 oid() const;
0082     QString version() const;
0083     QString changeset() const;
0084     QString uid() const;
0085     QString isVisible() const;
0086     QString user() const;
0087     QString timestamp() const;
0088     QString action() const;
0089     const char* nodeType() const override;
0090 
0091     void setId( qint64 id );
0092     void setVersion( const QString& version );
0093     void setChangeset( const QString& changeset );
0094     void setUid( const QString& uid );
0095     void setVisible( const QString& visible );
0096     void setUser( const QString& user );
0097     void setTimestamp( const QString& timestamp );
0098     void setAction( const QString& action );
0099 
0100     /**
0101      * @brief tagValue returns the value of the tag that has @p key as key
0102      * or an empty qstring if there is no such tag
0103      */
0104     QString tagValue( const QString &key ) const;
0105 
0106     /**
0107      * @brief addTag this function inserts a string key=value mapping,
0108      * equivalent to the \<tag k="@p key" v="@p value"\> osm core data
0109      * element
0110      */
0111     void addTag( const QString& key, const QString& value );
0112 
0113     /**
0114      * @brief removeTag removes the tag from the tag hash
0115      */
0116     void removeTag( const QString& key );
0117 
0118     /**
0119      * @brief containsTag returns true if the tag hash contains an entry with
0120      * the @p key as key and @p value as value
0121      */
0122     bool containsTag( const QString& key, const QString& value ) const;
0123 
0124     /**
0125      * @brief containsTagKey returns true if the tag hash contains an entry with
0126      * the @p key as key
0127      */
0128     bool containsTagKey( const QString& key ) const;
0129 
0130     /**
0131      * @brief tagValue returns a pointer to the tag that has @p key as key
0132      * or the end iterator if there is no such tag
0133      */
0134     QHash<QString, QString>::const_iterator findTag(const QString &key) const;
0135 
0136     /**
0137      * @brief iterators for the tags hash.
0138      */
0139     QHash< QString, QString >::const_iterator tagsBegin() const;
0140     QHash< QString, QString >::const_iterator tagsEnd() const;
0141 
0142     /**
0143      * @brief this function returns the osmData associated with a nd
0144      */
0145     OsmPlacemarkData &nodeReference( const GeoDataCoordinates& coordinates );
0146     OsmPlacemarkData nodeReference( const GeoDataCoordinates& coordinates ) const;
0147 
0148     /**
0149      * @brief addRef this function inserts a GeoDataCoordinates = OsmPlacemarkData
0150      * mapping into the reference hash, equivalent to the \<member ref="@p key" \>
0151      * osm core data element
0152      */
0153     void addNodeReference( const GeoDataCoordinates& key, const OsmPlacemarkData &value );
0154     void removeNodeReference( const GeoDataCoordinates& key );
0155     bool containsNodeReference( const GeoDataCoordinates& key ) const;
0156 
0157     /**
0158      * @brief changeNodeReference is a convenience function that allows the quick change of
0159      * a node hash entry. This is generally used to update the osm data in case
0160      * nodes are being moved in the editor.
0161      */
0162     void changeNodeReference( const GeoDataCoordinates& oldKey, const GeoDataCoordinates &newKey );
0163 
0164     /**
0165      * @brief this function returns the osmData associated with a member boundary's index
0166      * -1 represents the outer boundary of a polygon, and 0,1,2... the inner boundaries,
0167      * in the order provided by polygon->innerBoundaries();
0168      */
0169     OsmPlacemarkData &memberReference( int key );
0170     OsmPlacemarkData memberReference( int key ) const;
0171 
0172     /**
0173      * @brief addRef this function inserts a int = OsmplacemarkData
0174      * mapping into the reference hash, equivalent to the osm \<nd ref="@p boundary of index @key" \>
0175      * core data element
0176      * @see m_memberReferences
0177      */
0178     void addMemberReference( int key, const OsmPlacemarkData &value );
0179     void removeMemberReference( int key );
0180     bool containsMemberReference( int key ) const;
0181 
0182     /**
0183      * @brief addRelation calling this makes the osm placemark a member of the relation
0184      * with @p id as id, while having the role @p role
0185      */
0186     void addRelation( qint64 id, OsmType type, const QString &role );
0187     void removeRelation( qint64 id );
0188     bool containsRelation( qint64 id ) const;
0189 
0190     QHash< OsmIdentifier, QString >::const_iterator relationReferencesBegin() const;
0191     QHash< OsmIdentifier, QString >::const_iterator relationReferencesEnd() const;
0192 
0193     /**
0194      * @brief isNull returns false if the osmData is loaded from a source
0195      * or true if its just default constructed
0196      */
0197     bool isNull() const;
0198 
0199     /**
0200      * @brief isEmpty returns true if no attribute other than the id has been set
0201      */
0202     bool isEmpty() const;
0203 
0204     /**
0205      * @brief fromParserAttributes is a convenience function that parses all osm-related
0206      * arguments of a tag
0207      * @return an OsmPlacemarkData object containing all the necessary data
0208      */
0209     static OsmPlacemarkData fromParserAttributes( const QXmlStreamAttributes &attributes );
0210 
0211     /**
0212      * Return the insternal instance of the hash-table functions container.
0213      */
0214     OsmPlacemarkDataHashRef* hRef() const;
0215 
0216 private:
0217 
0218     qint64 m_id;
0219     QHash<QString, QString> m_tags;
0220 
0221     /**
0222      * @brief m_relationReferences is used to store the relations the placemark is part of
0223      * and the role it has within them.
0224      * Eg. an entry ( "123", "stop" ) means that the parent placemark is a member of
0225      * the relation with id "123", while having the "stop" role
0226      */
0227     QHash<OsmIdentifier, QString> m_relationReferences;
0228 
0229     /**
0230      * Store the insternal instance of the hash-table functions container.
0231      */
0232     QSharedPointer<OsmPlacemarkDataHashRef> m_href;
0233 };
0234 
0235 /**
0236  * Container to host hash-table functions with OsmPlacemarkData as values.
0237  * This container is necessary with Qt 6.6 under MSVC 2022 as compiler refuse to build
0238  * a QHash of a not fully defined class as value.
0239  *
0240  * E:\dk\x64-windows\include\Qt6\QtCore/qhash.h(76,7): error C2079: 'QHashPrivate::Node<Key,T>::value' uses undefined class 'Marble::OsmPlacemarkData' [C:\Users\gilles\Documents\marble\build.vcpkg\src\lib\marble\marblewidget.vcxproj]
0241  *          with
0242  *         [
0243  *             Key=Marble::GeoDataCoordinates,
0244  *             T=Marble::OsmPlacemarkData
0245  *         ]
0246  * E:\dk\x64-windows\include\Qt6\QtCore/qhash.h(858,1): message : see reference to class template instantiation 'QHashPrivate::Node<Key,T>' being compiled [C:\Users\gilles\Documents\marble\build.vcpkg\src\lib\marble\marblewidget.vcxproj]
0247  *         with
0248  *         [
0249  *             Key=Marble::GeoDataCoordinates,
0250  *             T=Marble::OsmPlacemarkData
0251  *         ]
0252  *
0253  */
0254 class DIGIKAM_EXPORT OsmPlacemarkDataHashRef
0255 {
0256 public:
0257 
0258     OsmPlacemarkDataHashRef();
0259 
0260     /**
0261      * @brief iterators for the reference hashes.
0262      */
0263     QHash< GeoDataCoordinates, OsmPlacemarkData > & nodeReferences();
0264     QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator nodeReferencesBegin() const;
0265     QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator nodeReferencesEnd() const;
0266 
0267     QHash< int, OsmPlacemarkData > & memberReferences();
0268     QHash< int, OsmPlacemarkData >::const_iterator memberReferencesBegin() const;
0269     QHash< int, OsmPlacemarkData >::const_iterator memberReferencesEnd() const;
0270 
0271     /**
0272      * @brief m_ndRefs is used to store a way's component nodes
0273      * ( It is empty for other placemark types )
0274      */
0275     QHash< GeoDataCoordinates, OsmPlacemarkData > m_nodeReferences;
0276 
0277     /**
0278      * @brief m_memberRefs is used to store a polygon's member boundaries
0279      *  the key represents the index of the boundary within the polygon geometry:
0280      *  -1 represents the outerBoundary, and 0,1,2... its innerBoundaries, in the
0281      *  order provided by polygon->innerBoundaries()
0282      */
0283     QHash<int, OsmPlacemarkData> m_memberReferences;
0284 };
0285 
0286 }
0287 
0288 // Makes qvariant_cast possible for OsmPlacemarkData objects
0289 Q_DECLARE_METATYPE( Marble::OsmPlacemarkData )
0290 
0291 #endif