File indexing completed on 2024-05-12 03:50:11

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2007 Murad Tagirov <tmurad@gmail.com>
0004 // SPDX-FileCopyrightText: 2009 Patrick Spendrin <ps_ml@gmx.de>
0005 //
0006 
0007 
0008 #include "GeoDataFeature.h"
0009 #include "GeoDataFeature_p.h"
0010 
0011 #include <QDataStream>
0012 #include <QSize>
0013 
0014 #include "MarbleDirs.h"
0015 #include "MarbleDebug.h"
0016 
0017 #include "GeoDataStyle.h"
0018 #include "GeoDataStyleMap.h"
0019 
0020 #include "GeoDataContainer.h"
0021 #include "GeoDataDocument.h"
0022 #include "GeoDataFolder.h"
0023 #include "GeoDataGroundOverlay.h"
0024 #include "GeoDataNetworkLink.h"
0025 #include "GeoDataNetworkLinkControl.h"
0026 #include "GeoDataPhotoOverlay.h"
0027 #include "GeoDataPlacemark.h"
0028 #include "GeoDataScreenOverlay.h"
0029 #include "GeoDataTour.h"
0030 #include "GeoDataRegion.h"
0031 #include "GeoDataCamera.h"
0032 
0033 namespace Marble
0034 {
0035 
0036 GeoDataFeature::GeoDataFeature()
0037     : d_ptr(new GeoDataFeaturePrivate())
0038 {
0039 }
0040 
0041 GeoDataFeature::GeoDataFeature( const GeoDataFeature& other )
0042     : GeoDataObject(),
0043       d_ptr(new GeoDataFeaturePrivate(*other.d_ptr))
0044 {
0045 }
0046 
0047 GeoDataFeature::GeoDataFeature( const QString& name )
0048     : d_ptr(new GeoDataFeaturePrivate())
0049 {
0050     d_ptr->m_name = name;
0051 }
0052 
0053 GeoDataFeature::GeoDataFeature(GeoDataFeaturePrivate *dd)
0054     : GeoDataObject(),
0055       d_ptr(dd)
0056 {
0057 }
0058 
0059 GeoDataFeature::GeoDataFeature(const GeoDataFeature& other, GeoDataFeaturePrivate *dd)
0060     : GeoDataObject(),
0061       d_ptr(dd)
0062 {
0063     Q_UNUSED(other);
0064     // TODO: some classes pass "other" on and thus get duplicated id, also in operator=. Align behaviour
0065 }
0066 
0067 GeoDataFeature::~GeoDataFeature()
0068 {
0069     delete d_ptr;
0070 }
0071 
0072 GeoDataFeature& GeoDataFeature::operator=( const GeoDataFeature& other )
0073 {
0074     if (this != &other) {
0075         *d_ptr = *other.d_ptr;
0076     }
0077 
0078     return *this;
0079 }
0080 
0081 bool GeoDataFeature::operator==(const GeoDataFeature &other) const
0082 {
0083     if (nodeType() != other.nodeType()) {
0084         return false;
0085     }
0086 
0087     if (nodeType() == GeoDataTypes::GeoDataDocumentType) {
0088         const GeoDataDocument &thisDoc = static_cast<const GeoDataDocument &>(*this);
0089         const GeoDataDocument &otherDoc = static_cast<const GeoDataDocument &>(other);
0090 
0091         return thisDoc == otherDoc;
0092     } else if (nodeType() == GeoDataTypes::GeoDataFolderType) {
0093         const GeoDataFolder &thisFolder = static_cast<const GeoDataFolder &>(*this);
0094         const GeoDataFolder &otherFolder = static_cast<const GeoDataFolder &>(other);
0095 
0096         return thisFolder == otherFolder;
0097     } else if (nodeType() == GeoDataTypes::GeoDataGroundOverlayType) {
0098         const GeoDataGroundOverlay &thisGO = static_cast<const GeoDataGroundOverlay &>(*this);
0099         const GeoDataGroundOverlay &otherGO = static_cast<const GeoDataGroundOverlay &>(other);
0100 
0101         return thisGO == otherGO;
0102     } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkType) {
0103         const GeoDataNetworkLink &thisNetLink = static_cast<const GeoDataNetworkLink &>(*this);
0104         const GeoDataNetworkLink &otherNetLink = static_cast<const GeoDataNetworkLink &>(other);
0105 
0106         return thisNetLink == otherNetLink;
0107     } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkControlType) {
0108         const GeoDataNetworkLinkControl &thisNLC = static_cast<const GeoDataNetworkLinkControl &>(*this);
0109         const GeoDataNetworkLinkControl &otherNLC = static_cast<const GeoDataNetworkLinkControl &>(other);
0110 
0111         return thisNLC == otherNLC;
0112     } else if (nodeType() == GeoDataTypes::GeoDataPhotoOverlayType) {
0113         const GeoDataPhotoOverlay &thisPO = static_cast<const GeoDataPhotoOverlay &>(*this);
0114         const GeoDataPhotoOverlay &otherPO = static_cast<const GeoDataPhotoOverlay &>(other);
0115 
0116         return thisPO == otherPO;
0117     } else if (nodeType() == GeoDataTypes::GeoDataPlacemarkType) {
0118         const GeoDataPlacemark &thisPM = static_cast<const GeoDataPlacemark &>(*this);
0119         const GeoDataPlacemark &otherPM = static_cast<const GeoDataPlacemark &>(other);
0120 
0121         return thisPM == otherPM;
0122     } else if (nodeType() == GeoDataTypes::GeoDataScreenOverlayType) {
0123         const GeoDataScreenOverlay &thisSO = static_cast<const GeoDataScreenOverlay &>(*this);
0124         const GeoDataScreenOverlay &otherSO = static_cast<const GeoDataScreenOverlay &>(other);
0125 
0126         return thisSO == otherSO;
0127     } else if (nodeType() == GeoDataTypes::GeoDataTourType) {
0128         const GeoDataTour &thisTour = static_cast<const GeoDataTour &>(*this);
0129         const GeoDataTour &otherTour = static_cast<const GeoDataTour &>(other);
0130 
0131         return thisTour == otherTour;
0132     }
0133 
0134     return false;
0135 }
0136 
0137 bool GeoDataFeature::equals( const GeoDataFeature &other ) const
0138 {
0139     Q_D(const GeoDataFeature);
0140     const GeoDataFeaturePrivate* const other_d = other.d_func();
0141 
0142     if (!GeoDataObject::equals(other) ||
0143         d->m_name != other_d->m_name ||
0144         d->m_styleUrl != other_d->m_styleUrl ||
0145         d->m_popularity != other_d->m_popularity ||
0146         d->m_zoomLevel != other_d->m_zoomLevel ||
0147         d->m_visible != other_d->m_visible ||
0148         d->m_role != other_d->m_role ||
0149         d->m_extendedData != other_d->m_extendedData ||
0150         *style() != *other.style()) {
0151         return false;
0152     }
0153 
0154     if ((!d->m_styleMap && other_d->m_styleMap) ||
0155         (d->m_styleMap && !other_d->m_styleMap)) {
0156         return false;
0157     }
0158 
0159     if ((d->m_styleMap && other_d->m_styleMap) &&
0160         (*d->m_styleMap != *other_d->m_styleMap)) {
0161         return false;
0162     }
0163 
0164     if ((!d->m_featureExtendedData && other_d->m_featureExtendedData && other_d->m_featureExtendedData->m_abstractView) ||
0165         (d->m_featureExtendedData && d->m_featureExtendedData->m_abstractView && !other_d->m_featureExtendedData)) {
0166         return false;
0167     }
0168 
0169     if ((d->m_featureExtendedData && other_d->m_featureExtendedData) &&
0170         (*d->m_featureExtendedData != *other_d->m_featureExtendedData)) {
0171         return false;
0172     }
0173 
0174     return true;
0175 }
0176 
0177 EnumFeatureId GeoDataFeature::featureId() const
0178 {
0179     Q_D(const GeoDataFeature);
0180     return d->featureId();
0181 }
0182 
0183 QString GeoDataFeature::name() const
0184 {
0185     Q_D(const GeoDataFeature);
0186     return d->m_name;
0187 }
0188 
0189 void GeoDataFeature::setName( const QString &value )
0190 {
0191     Q_D(GeoDataFeature);
0192     d->m_name = value;
0193 }
0194 
0195 GeoDataSnippet GeoDataFeature::snippet() const
0196 {
0197     Q_D(const GeoDataFeature);
0198     return d->featureExtendedData().m_snippet;
0199 }
0200 
0201 void GeoDataFeature::setSnippet( const GeoDataSnippet &snippet )
0202 {
0203     Q_D(GeoDataFeature);
0204     d->featureExtendedData().m_snippet = snippet;
0205 }
0206 
0207 QString GeoDataFeature::address() const
0208 {
0209     Q_D(const GeoDataFeature);
0210     if (!d->m_featureExtendedData) {
0211         return QString();
0212     }
0213 
0214     return d->featureExtendedData().m_address;
0215 }
0216 
0217 void GeoDataFeature::setAddress( const QString &value)
0218 {
0219     Q_D(GeoDataFeature);
0220     if (value.isEmpty() && !d->m_featureExtendedData) {
0221         return; // nothing to change
0222     }
0223 
0224     d->featureExtendedData().m_address = value;
0225 }
0226 
0227 QString GeoDataFeature::phoneNumber() const
0228 {
0229     Q_D(const GeoDataFeature);
0230     if (!d->m_featureExtendedData) {
0231         return QString();
0232     }
0233 
0234     return d->featureExtendedData().m_phoneNumber;
0235 }
0236 
0237 void GeoDataFeature::setPhoneNumber( const QString &value)
0238 {
0239     Q_D(GeoDataFeature);
0240     if (value.isEmpty() && !d->m_featureExtendedData) {
0241         return; // nothing to change
0242     }
0243 
0244     d->featureExtendedData().m_phoneNumber = value;
0245 }
0246 
0247 QString GeoDataFeature::description() const
0248 {
0249     Q_D(const GeoDataFeature);
0250     if (!d->m_featureExtendedData) {
0251         return QString();
0252     }
0253 
0254     return d->featureExtendedData().m_description;
0255 }
0256 
0257 void GeoDataFeature::setDescription( const QString &value)
0258 {
0259     Q_D(GeoDataFeature);
0260     if (value.isEmpty() && !d->m_featureExtendedData) {
0261         return; // nothing to change
0262     }
0263 
0264     d->featureExtendedData().m_description = value;
0265 }
0266 
0267 bool GeoDataFeature::descriptionIsCDATA() const
0268 {
0269     Q_D(const GeoDataFeature);
0270     if (!d->m_featureExtendedData) {
0271         return false;
0272     }
0273 
0274     return d->featureExtendedData().m_descriptionCDATA;
0275 }
0276 
0277 void GeoDataFeature::setDescriptionCDATA( bool cdata )
0278 {
0279     Q_D(GeoDataFeature);
0280     d->featureExtendedData().m_descriptionCDATA = cdata;
0281 }
0282 
0283 const GeoDataAbstractView* GeoDataFeature::abstractView() const
0284 {
0285     Q_D(const GeoDataFeature);
0286     if (!d->m_featureExtendedData) {
0287         return nullptr;
0288     }
0289 
0290     return d->featureExtendedData().m_abstractView;
0291 }
0292 
0293 GeoDataAbstractView *GeoDataFeature::abstractView()
0294 {
0295     // FIXME: Calling detach() doesn't help at all because the m_abstractView
0296     // object isn't actually copied in the Private class as well.
0297     // detach();
0298 
0299     Q_D(GeoDataFeature);
0300     return d->featureExtendedData().m_abstractView;
0301 }
0302 
0303 void GeoDataFeature::setAbstractView( GeoDataAbstractView *abstractView )
0304 {
0305     Q_D(GeoDataFeature);
0306     if (abstractView == nullptr && !d->m_featureExtendedData) {
0307         return; // nothing to change
0308     }
0309 
0310     d->featureExtendedData().m_abstractView = abstractView;
0311 }
0312 
0313 QString GeoDataFeature::styleUrl() const
0314 {
0315     Q_D(const GeoDataFeature);
0316     return d->m_styleUrl;
0317 }
0318 
0319 void GeoDataFeature::setStyleUrl( const QString &value )
0320 {
0321     Q_D(GeoDataFeature);
0322     d->m_styleUrl = value;
0323 
0324     if ( value.isEmpty() ) {
0325         d->m_style = GeoDataStyle::Ptr();
0326         return;
0327     }
0328 
0329     QString styleUrl = value;
0330     styleUrl.remove(QLatin1Char('#'));
0331 
0332     for (auto object = parent(); object != nullptr; object = object->parent()) {
0333         if (GeoDataDocument *doc = geodata_cast<GeoDataDocument>(object)) {
0334             GeoDataStyleMap &styleMap = doc->styleMap( styleUrl );
0335             const QString normalStyleUrl = styleMap.value(QStringLiteral("normal"));
0336             if (!normalStyleUrl.isEmpty()) {
0337                 styleUrl = normalStyleUrl;
0338                 styleUrl.remove(QLatin1Char('#'));
0339             }
0340             // Not calling setStyle here because we don't want
0341             // re-parenting of the style
0342             d->m_style = doc->style( styleUrl );
0343             break;
0344         }
0345     }
0346 }
0347 
0348 bool GeoDataFeature::isVisible() const
0349 {
0350     Q_D(const GeoDataFeature);
0351     return d->m_visible;
0352 }
0353 
0354 void GeoDataFeature::setVisible( bool value )
0355 {
0356     Q_D(GeoDataFeature);
0357     d->m_visible = value;
0358 }
0359 
0360 bool GeoDataFeature::isGloballyVisible() const
0361 {
0362     Q_D(const GeoDataFeature);
0363     if ( parent() == nullptr ) {
0364         return d->m_visible;
0365     }
0366     const GeoDataContainer *container = static_cast<const GeoDataContainer*>(parent());
0367     return d->m_visible && container->isGloballyVisible();
0368 }
0369 
0370 
0371 const GeoDataTimeSpan &GeoDataFeature::timeSpan() const
0372 {
0373     Q_D(const GeoDataFeature);
0374     return d->featureExtendedData().m_timeSpan;
0375 }
0376 
0377 GeoDataTimeSpan &GeoDataFeature::timeSpan()
0378 {
0379     Q_D(GeoDataFeature);
0380     return d->featureExtendedData().m_timeSpan;
0381 }
0382 
0383 void GeoDataFeature::setTimeSpan( const GeoDataTimeSpan &timeSpan )
0384 {
0385     Q_D(GeoDataFeature);
0386     d->featureExtendedData().m_timeSpan = timeSpan;
0387 }
0388 
0389 const GeoDataTimeStamp &GeoDataFeature::timeStamp() const
0390 {
0391     Q_D(const GeoDataFeature);
0392     return d->featureExtendedData().m_timeStamp;
0393 }
0394 
0395 GeoDataTimeStamp &GeoDataFeature::timeStamp()
0396 {
0397     Q_D(GeoDataFeature);
0398     return d->featureExtendedData().m_timeStamp;
0399 }
0400 
0401 void GeoDataFeature::setTimeStamp( const GeoDataTimeStamp &timeStamp )
0402 {
0403     Q_D(GeoDataFeature);
0404     d->featureExtendedData().m_timeStamp = timeStamp;
0405 }
0406 
0407 const GeoDataExtendedData &GeoDataFeature::extendedData() const
0408 {
0409     Q_D(const GeoDataFeature);
0410     return d->m_extendedData;
0411 }
0412 
0413 GeoDataStyle::ConstPtr GeoDataFeature::style() const
0414 {
0415     Q_D(const GeoDataFeature);
0416     if (d->m_style) {
0417         return d->m_style;
0418     }
0419 
0420     static const QSharedPointer<const GeoDataStyle> s_defaultStyle(new GeoDataStyle);
0421     return s_defaultStyle;
0422 }
0423 
0424 GeoDataStyle::ConstPtr GeoDataFeature::customStyle() const
0425 {
0426     Q_D(const GeoDataFeature);
0427     return d->m_style;
0428 }
0429 
0430 void GeoDataFeature::setStyle( const GeoDataStyle::Ptr &style )
0431 {
0432     Q_D(GeoDataFeature);
0433     if (style)
0434         style->setParent( this );
0435     d->m_style = style;
0436 }
0437 
0438 GeoDataExtendedData& GeoDataFeature::extendedData()
0439 {
0440     Q_D(GeoDataFeature);
0441     return d->m_extendedData;
0442 }
0443 
0444 void GeoDataFeature::setExtendedData( const GeoDataExtendedData& extendedData )
0445 {
0446     Q_D(GeoDataFeature);
0447     d->m_extendedData = extendedData;
0448 }
0449 
0450 const GeoDataRegion& GeoDataFeature::region() const
0451 {
0452     Q_D(const GeoDataFeature);
0453     return d->featureExtendedData().m_region;
0454 }
0455 
0456 GeoDataRegion& GeoDataFeature::region()
0457 {
0458     Q_D(GeoDataFeature);
0459     return d->featureExtendedData().m_region;
0460 }
0461 
0462 void GeoDataFeature::setRegion( const GeoDataRegion& region )
0463 {
0464     Q_D(GeoDataFeature);
0465     d->featureExtendedData().m_region = region;
0466 }
0467 
0468 const QString GeoDataFeature::role() const
0469 {
0470     Q_D(const GeoDataFeature);
0471     return d->m_role;
0472 }
0473 
0474 void GeoDataFeature::setRole( const QString &role )
0475 {
0476     Q_D(GeoDataFeature);
0477     d->m_role = role;
0478 }
0479 
0480 const GeoDataStyleMap* GeoDataFeature::styleMap() const
0481 {
0482     Q_D(const GeoDataFeature);
0483     return d->m_styleMap;
0484 }
0485 
0486 void GeoDataFeature::setStyleMap( const GeoDataStyleMap* styleMap )
0487 {
0488     Q_D(GeoDataFeature);
0489     d->m_styleMap = styleMap;
0490 }
0491 
0492 int GeoDataFeature::zoomLevel() const
0493 {
0494     Q_D(const GeoDataFeature);
0495     return d->m_zoomLevel;
0496 }
0497 
0498 void GeoDataFeature::setZoomLevel( int zoomLevel )
0499 {
0500     Q_D(GeoDataFeature);
0501     d->m_zoomLevel = zoomLevel;
0502 }
0503 
0504 qint64 GeoDataFeature::popularity() const
0505 {
0506     Q_D(const GeoDataFeature);
0507     return d->m_popularity;
0508 }
0509 
0510 void GeoDataFeature::setPopularity( qint64 popularity )
0511 {
0512     Q_D(GeoDataFeature);
0513     d->m_popularity = popularity;
0514 }
0515 
0516 void GeoDataFeature::pack( QDataStream& stream ) const
0517 {
0518     Q_D(const GeoDataFeature);
0519 
0520     GeoDataObject::pack( stream );
0521 
0522     stream << d->m_name;
0523     stream << d->featureExtendedData().m_address;
0524     stream << d->featureExtendedData().m_phoneNumber;
0525     stream << d->featureExtendedData().m_description;
0526     stream << d->m_visible;
0527 //    stream << d->m_visualCategory;
0528     stream << d->m_role;
0529     stream << d->m_popularity;
0530     stream << d->m_zoomLevel;
0531 }
0532 
0533 void GeoDataFeature::unpack( QDataStream& stream )
0534 {
0535     Q_D(GeoDataFeature);
0536     GeoDataObject::unpack( stream );
0537 
0538     stream >> d->m_name;
0539     stream >> d->featureExtendedData().m_address;
0540     stream >> d->featureExtendedData().m_phoneNumber;
0541     stream >> d->featureExtendedData().m_description;
0542     stream >> d->m_visible;
0543 //    stream >> (int)d->m_visualCategory;
0544     stream >> d->m_role;
0545     stream >> d->m_popularity;
0546     stream >> d->m_zoomLevel;
0547 }
0548 
0549 }