File indexing completed on 2025-01-05 03:58:55
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 "digikam_debug.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 }