1 // SPDX-License-Identifier: LGPL-2.1-or-later 2 // 3 // SPDX-FileCopyrightText: 2007 Murad Tagirov <tmurad@gmail.com> 4 // SPDX-FileCopyrightText: 2009 Patrick Spendrin <ps_ml@gmx.de> 5 // 6 7 8 #include "GeoDataFeature.h" 9 #include "GeoDataFeature_p.h" 10 11 #include <QDataStream> 12 #include <QSize> 13 14 #include "MarbleDirs.h" 15 #include "MarbleDebug.h" 16 17 #include "GeoDataStyle.h" 18 #include "GeoDataStyleMap.h" 19 20 #include "GeoDataContainer.h" 21 #include "GeoDataDocument.h" 22 #include "GeoDataFolder.h" 23 #include "GeoDataGroundOverlay.h" 24 #include "GeoDataNetworkLink.h" 25 #include "GeoDataNetworkLinkControl.h" 26 #include "GeoDataPhotoOverlay.h" 27 #include "GeoDataPlacemark.h" 28 #include "GeoDataScreenOverlay.h" 29 #include "GeoDataTour.h" 30 #include "GeoDataRegion.h" 31 #include "GeoDataCamera.h" 32 33 namespace Marble 34 { 35 36 const QSharedPointer<const GeoDataStyle> GeoDataFeaturePrivate::s_defaultStyle(new GeoDataStyle); 37 GeoDataFeature()38GeoDataFeature::GeoDataFeature() 39 : d_ptr(new GeoDataFeaturePrivate()) 40 { 41 } 42 GeoDataFeature(const GeoDataFeature & other)43GeoDataFeature::GeoDataFeature( const GeoDataFeature& other ) 44 : GeoDataObject(), 45 d_ptr(new GeoDataFeaturePrivate(*other.d_ptr)) 46 { 47 } 48 GeoDataFeature(const QString & name)49GeoDataFeature::GeoDataFeature( const QString& name ) 50 : d_ptr(new GeoDataFeaturePrivate()) 51 { 52 d_ptr->m_name = name; 53 } 54 GeoDataFeature(GeoDataFeaturePrivate * dd)55GeoDataFeature::GeoDataFeature(GeoDataFeaturePrivate *dd) 56 : GeoDataObject(), 57 d_ptr(dd) 58 { 59 } 60 GeoDataFeature(const GeoDataFeature & other,GeoDataFeaturePrivate * dd)61GeoDataFeature::GeoDataFeature(const GeoDataFeature& other, GeoDataFeaturePrivate *dd) 62 : GeoDataObject(), 63 d_ptr(dd) 64 { 65 Q_UNUSED(other); 66 // TODO: some classes pass "other" on and thus get duplicated id, also in operator=. Align behaviour 67 } 68 ~GeoDataFeature()69GeoDataFeature::~GeoDataFeature() 70 { 71 delete d_ptr; 72 } 73 operator =(const GeoDataFeature & other)74GeoDataFeature& GeoDataFeature::operator=( const GeoDataFeature& other ) 75 { 76 if (this != &other) { 77 *d_ptr = *other.d_ptr; 78 } 79 80 return *this; 81 } 82 operator ==(const GeoDataFeature & other) const83bool GeoDataFeature::operator==(const GeoDataFeature &other) const 84 { 85 if (nodeType() != other.nodeType()) { 86 return false; 87 } 88 89 if (nodeType() == GeoDataTypes::GeoDataDocumentType) { 90 const GeoDataDocument &thisDoc = static_cast<const GeoDataDocument &>(*this); 91 const GeoDataDocument &otherDoc = static_cast<const GeoDataDocument &>(other); 92 93 return thisDoc == otherDoc; 94 } else if (nodeType() == GeoDataTypes::GeoDataFolderType) { 95 const GeoDataFolder &thisFolder = static_cast<const GeoDataFolder &>(*this); 96 const GeoDataFolder &otherFolder = static_cast<const GeoDataFolder &>(other); 97 98 return thisFolder == otherFolder; 99 } else if (nodeType() == GeoDataTypes::GeoDataGroundOverlayType) { 100 const GeoDataGroundOverlay &thisGO = static_cast<const GeoDataGroundOverlay &>(*this); 101 const GeoDataGroundOverlay &otherGO = static_cast<const GeoDataGroundOverlay &>(other); 102 103 return thisGO == otherGO; 104 } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkType) { 105 const GeoDataNetworkLink &thisNetLink = static_cast<const GeoDataNetworkLink &>(*this); 106 const GeoDataNetworkLink &otherNetLink = static_cast<const GeoDataNetworkLink &>(other); 107 108 return thisNetLink == otherNetLink; 109 } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkControlType) { 110 const GeoDataNetworkLinkControl &thisNLC = static_cast<const GeoDataNetworkLinkControl &>(*this); 111 const GeoDataNetworkLinkControl &otherNLC = static_cast<const GeoDataNetworkLinkControl &>(other); 112 113 return thisNLC == otherNLC; 114 } else if (nodeType() == GeoDataTypes::GeoDataPhotoOverlayType) { 115 const GeoDataPhotoOverlay &thisPO = static_cast<const GeoDataPhotoOverlay &>(*this); 116 const GeoDataPhotoOverlay &otherPO = static_cast<const GeoDataPhotoOverlay &>(other); 117 118 return thisPO == otherPO; 119 } else if (nodeType() == GeoDataTypes::GeoDataPlacemarkType) { 120 const GeoDataPlacemark &thisPM = static_cast<const GeoDataPlacemark &>(*this); 121 const GeoDataPlacemark &otherPM = static_cast<const GeoDataPlacemark &>(other); 122 123 return thisPM == otherPM; 124 } else if (nodeType() == GeoDataTypes::GeoDataScreenOverlayType) { 125 const GeoDataScreenOverlay &thisSO = static_cast<const GeoDataScreenOverlay &>(*this); 126 const GeoDataScreenOverlay &otherSO = static_cast<const GeoDataScreenOverlay &>(other); 127 128 return thisSO == otherSO; 129 } else if (nodeType() == GeoDataTypes::GeoDataTourType) { 130 const GeoDataTour &thisTour = static_cast<const GeoDataTour &>(*this); 131 const GeoDataTour &otherTour = static_cast<const GeoDataTour &>(other); 132 133 return thisTour == otherTour; 134 } 135 136 return false; 137 } 138 equals(const GeoDataFeature & other) const139bool GeoDataFeature::equals( const GeoDataFeature &other ) const 140 { 141 Q_D(const GeoDataFeature); 142 const GeoDataFeaturePrivate* const other_d = other.d_func(); 143 144 if (!GeoDataObject::equals(other) || 145 d->m_name != other_d->m_name || 146 d->m_styleUrl != other_d->m_styleUrl || 147 d->m_popularity != other_d->m_popularity || 148 d->m_zoomLevel != other_d->m_zoomLevel || 149 d->m_visible != other_d->m_visible || 150 d->m_role != other_d->m_role || 151 d->m_extendedData != other_d->m_extendedData || 152 *style() != *other.style()) { 153 return false; 154 } 155 156 if ((!d->m_styleMap && other_d->m_styleMap) || 157 (d->m_styleMap && !other_d->m_styleMap)) { 158 return false; 159 } 160 161 if ((d->m_styleMap && other_d->m_styleMap) && 162 (*d->m_styleMap != *other_d->m_styleMap)) { 163 return false; 164 } 165 166 if ((!d->m_featureExtendedData && other_d->m_featureExtendedData && other_d->m_featureExtendedData->m_abstractView) || 167 (d->m_featureExtendedData && d->m_featureExtendedData->m_abstractView && !other_d->m_featureExtendedData)) { 168 return false; 169 } 170 171 if ((d->m_featureExtendedData && other_d->m_featureExtendedData) && 172 (*d->m_featureExtendedData != *other_d->m_featureExtendedData)) { 173 return false; 174 } 175 176 return true; 177 } 178 featureId() const179EnumFeatureId GeoDataFeature::featureId() const 180 { 181 Q_D(const GeoDataFeature); 182 return d->featureId(); 183 } 184 name() const185QString GeoDataFeature::name() const 186 { 187 Q_D(const GeoDataFeature); 188 return d->m_name; 189 } 190 setName(const QString & value)191void GeoDataFeature::setName( const QString &value ) 192 { 193 Q_D(GeoDataFeature); 194 d->m_name = value; 195 } 196 snippet() const197GeoDataSnippet GeoDataFeature::snippet() const 198 { 199 Q_D(const GeoDataFeature); 200 return d->featureExtendedData().m_snippet; 201 } 202 setSnippet(const GeoDataSnippet & snippet)203void GeoDataFeature::setSnippet( const GeoDataSnippet &snippet ) 204 { 205 Q_D(GeoDataFeature); 206 d->featureExtendedData().m_snippet = snippet; 207 } 208 address() const209QString GeoDataFeature::address() const 210 { 211 Q_D(const GeoDataFeature); 212 if (!d->m_featureExtendedData) { 213 return QString(); 214 } 215 216 return d->featureExtendedData().m_address; 217 } 218 setAddress(const QString & value)219void GeoDataFeature::setAddress( const QString &value) 220 { 221 Q_D(GeoDataFeature); 222 if (value.isEmpty() && !d->m_featureExtendedData) { 223 return; // nothing to change 224 } 225 226 d->featureExtendedData().m_address = value; 227 } 228 phoneNumber() const229QString GeoDataFeature::phoneNumber() const 230 { 231 Q_D(const GeoDataFeature); 232 if (!d->m_featureExtendedData) { 233 return QString(); 234 } 235 236 return d->featureExtendedData().m_phoneNumber; 237 } 238 setPhoneNumber(const QString & value)239void GeoDataFeature::setPhoneNumber( const QString &value) 240 { 241 Q_D(GeoDataFeature); 242 if (value.isEmpty() && !d->m_featureExtendedData) { 243 return; // nothing to change 244 } 245 246 d->featureExtendedData().m_phoneNumber = value; 247 } 248 description() const249QString GeoDataFeature::description() const 250 { 251 Q_D(const GeoDataFeature); 252 if (!d->m_featureExtendedData) { 253 return QString(); 254 } 255 256 return d->featureExtendedData().m_description; 257 } 258 setDescription(const QString & value)259void GeoDataFeature::setDescription( const QString &value) 260 { 261 Q_D(GeoDataFeature); 262 if (value.isEmpty() && !d->m_featureExtendedData) { 263 return; // nothing to change 264 } 265 266 d->featureExtendedData().m_description = value; 267 } 268 descriptionIsCDATA() const269bool GeoDataFeature::descriptionIsCDATA() const 270 { 271 Q_D(const GeoDataFeature); 272 if (!d->m_featureExtendedData) { 273 return false; 274 } 275 276 return d->featureExtendedData().m_descriptionCDATA; 277 } 278 setDescriptionCDATA(bool cdata)279void GeoDataFeature::setDescriptionCDATA( bool cdata ) 280 { 281 Q_D(GeoDataFeature); 282 d->featureExtendedData().m_descriptionCDATA = cdata; 283 } 284 abstractView() const285const GeoDataAbstractView* GeoDataFeature::abstractView() const 286 { 287 Q_D(const GeoDataFeature); 288 if (!d->m_featureExtendedData) { 289 return nullptr; 290 } 291 292 return d->featureExtendedData().m_abstractView; 293 } 294 abstractView()295GeoDataAbstractView *GeoDataFeature::abstractView() 296 { 297 // FIXME: Calling detach() doesn't help at all because the m_abstractView 298 // object isn't actually copied in the Private class as well. 299 // detach(); 300 301 Q_D(GeoDataFeature); 302 return d->featureExtendedData().m_abstractView; 303 } 304 setAbstractView(GeoDataAbstractView * abstractView)305void GeoDataFeature::setAbstractView( GeoDataAbstractView *abstractView ) 306 { 307 Q_D(GeoDataFeature); 308 if (abstractView == nullptr && !d->m_featureExtendedData) { 309 return; // nothing to change 310 } 311 312 d->featureExtendedData().m_abstractView = abstractView; 313 } 314 styleUrl() const315QString GeoDataFeature::styleUrl() const 316 { 317 Q_D(const GeoDataFeature); 318 return d->m_styleUrl; 319 } 320 setStyleUrl(const QString & value)321void GeoDataFeature::setStyleUrl( const QString &value ) 322 { 323 Q_D(GeoDataFeature); 324 d->m_styleUrl = value; 325 326 if ( value.isEmpty() ) { 327 d->m_style = GeoDataStyle::Ptr(); 328 return; 329 } 330 331 QString styleUrl = value; 332 styleUrl.remove(QLatin1Char('#')); 333 334 for (auto object = parent(); object != nullptr; object = object->parent()) { 335 if (GeoDataDocument *doc = geodata_cast<GeoDataDocument>(object)) { 336 GeoDataStyleMap &styleMap = doc->styleMap( styleUrl ); 337 const QString normalStyleUrl = styleMap.value(QStringLiteral("normal")); 338 if (!normalStyleUrl.isEmpty()) { 339 styleUrl = normalStyleUrl; 340 styleUrl.remove(QLatin1Char('#')); 341 } 342 // Not calling setStyle here because we don't want 343 // re-parenting of the style 344 d->m_style = doc->style( styleUrl ); 345 break; 346 } 347 } 348 } 349 isVisible() const350bool GeoDataFeature::isVisible() const 351 { 352 Q_D(const GeoDataFeature); 353 return d->m_visible; 354 } 355 setVisible(bool value)356void GeoDataFeature::setVisible( bool value ) 357 { 358 Q_D(GeoDataFeature); 359 d->m_visible = value; 360 } 361 isGloballyVisible() const362bool GeoDataFeature::isGloballyVisible() const 363 { 364 Q_D(const GeoDataFeature); 365 if ( parent() == nullptr ) { 366 return d->m_visible; 367 } 368 const GeoDataContainer *container = static_cast<const GeoDataContainer*>(parent()); 369 return d->m_visible && container->isGloballyVisible(); 370 } 371 372 timeSpan() const373const GeoDataTimeSpan &GeoDataFeature::timeSpan() const 374 { 375 Q_D(const GeoDataFeature); 376 return d->featureExtendedData().m_timeSpan; 377 } 378 timeSpan()379GeoDataTimeSpan &GeoDataFeature::timeSpan() 380 { 381 Q_D(GeoDataFeature); 382 return d->featureExtendedData().m_timeSpan; 383 } 384 setTimeSpan(const GeoDataTimeSpan & timeSpan)385void GeoDataFeature::setTimeSpan( const GeoDataTimeSpan &timeSpan ) 386 { 387 Q_D(GeoDataFeature); 388 d->featureExtendedData().m_timeSpan = timeSpan; 389 } 390 timeStamp() const391const GeoDataTimeStamp &GeoDataFeature::timeStamp() const 392 { 393 Q_D(const GeoDataFeature); 394 return d->featureExtendedData().m_timeStamp; 395 } 396 timeStamp()397GeoDataTimeStamp &GeoDataFeature::timeStamp() 398 { 399 Q_D(GeoDataFeature); 400 return d->featureExtendedData().m_timeStamp; 401 } 402 setTimeStamp(const GeoDataTimeStamp & timeStamp)403void GeoDataFeature::setTimeStamp( const GeoDataTimeStamp &timeStamp ) 404 { 405 Q_D(GeoDataFeature); 406 d->featureExtendedData().m_timeStamp = timeStamp; 407 } 408 extendedData() const409const GeoDataExtendedData &GeoDataFeature::extendedData() const 410 { 411 Q_D(const GeoDataFeature); 412 return d->m_extendedData; 413 } 414 style() const415GeoDataStyle::ConstPtr GeoDataFeature::style() const 416 { 417 Q_D(const GeoDataFeature); 418 if (d->m_style) { 419 return d->m_style; 420 } 421 422 return GeoDataFeaturePrivate::s_defaultStyle; 423 } 424 customStyle() const425GeoDataStyle::ConstPtr GeoDataFeature::customStyle() const 426 { 427 Q_D(const GeoDataFeature); 428 return d->m_style; 429 } 430 setStyle(const GeoDataStyle::Ptr & style)431void GeoDataFeature::setStyle( const GeoDataStyle::Ptr &style ) 432 { 433 Q_D(GeoDataFeature); 434 if (style) 435 style->setParent( this ); 436 d->m_style = style; 437 } 438 extendedData()439GeoDataExtendedData& GeoDataFeature::extendedData() 440 { 441 Q_D(GeoDataFeature); 442 return d->m_extendedData; 443 } 444 setExtendedData(const GeoDataExtendedData & extendedData)445void GeoDataFeature::setExtendedData( const GeoDataExtendedData& extendedData ) 446 { 447 Q_D(GeoDataFeature); 448 d->m_extendedData = extendedData; 449 } 450 region() const451const GeoDataRegion& GeoDataFeature::region() const 452 { 453 Q_D(const GeoDataFeature); 454 return d->featureExtendedData().m_region; 455 } 456 region()457GeoDataRegion& GeoDataFeature::region() 458 { 459 Q_D(GeoDataFeature); 460 return d->featureExtendedData().m_region; 461 } 462 setRegion(const GeoDataRegion & region)463void GeoDataFeature::setRegion( const GeoDataRegion& region ) 464 { 465 Q_D(GeoDataFeature); 466 d->featureExtendedData().m_region = region; 467 } 468 role() const469const QString GeoDataFeature::role() const 470 { 471 Q_D(const GeoDataFeature); 472 return d->m_role; 473 } 474 setRole(const QString & role)475void GeoDataFeature::setRole( const QString &role ) 476 { 477 Q_D(GeoDataFeature); 478 d->m_role = role; 479 } 480 styleMap() const481const GeoDataStyleMap* GeoDataFeature::styleMap() const 482 { 483 Q_D(const GeoDataFeature); 484 return d->m_styleMap; 485 } 486 setStyleMap(const GeoDataStyleMap * styleMap)487void GeoDataFeature::setStyleMap( const GeoDataStyleMap* styleMap ) 488 { 489 Q_D(GeoDataFeature); 490 d->m_styleMap = styleMap; 491 } 492 zoomLevel() const493int GeoDataFeature::zoomLevel() const 494 { 495 Q_D(const GeoDataFeature); 496 return d->m_zoomLevel; 497 } 498 setZoomLevel(int zoomLevel)499void GeoDataFeature::setZoomLevel( int zoomLevel ) 500 { 501 Q_D(GeoDataFeature); 502 d->m_zoomLevel = zoomLevel; 503 } 504 popularity() const505qint64 GeoDataFeature::popularity() const 506 { 507 Q_D(const GeoDataFeature); 508 return d->m_popularity; 509 } 510 setPopularity(qint64 popularity)511void GeoDataFeature::setPopularity( qint64 popularity ) 512 { 513 Q_D(GeoDataFeature); 514 d->m_popularity = popularity; 515 } 516 pack(QDataStream & stream) const517void GeoDataFeature::pack( QDataStream& stream ) const 518 { 519 Q_D(const GeoDataFeature); 520 521 GeoDataObject::pack( stream ); 522 523 stream << d->m_name; 524 stream << d->featureExtendedData().m_address; 525 stream << d->featureExtendedData().m_phoneNumber; 526 stream << d->featureExtendedData().m_description; 527 stream << d->m_visible; 528 // stream << d->m_visualCategory; 529 stream << d->m_role; 530 stream << d->m_popularity; 531 stream << d->m_zoomLevel; 532 } 533 unpack(QDataStream & stream)534void GeoDataFeature::unpack( QDataStream& stream ) 535 { 536 Q_D(GeoDataFeature); 537 GeoDataObject::unpack( stream ); 538 539 stream >> d->m_name; 540 stream >> d->featureExtendedData().m_address; 541 stream >> d->featureExtendedData().m_phoneNumber; 542 stream >> d->featureExtendedData().m_description; 543 stream >> d->m_visible; 544 // stream >> (int)d->m_visualCategory; 545 stream >> d->m_role; 546 stream >> d->m_popularity; 547 stream >> d->m_zoomLevel; 548 } 549 550 } 551