Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdeclarativeplace.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
8
9#include <QtCore/QCoreApplication>
10#include <QtCore/QMetaObject>
11#include <QtQml/QQmlEngine>
12#include <QtQml/QQmlInfo>
13#include <QtLocation/QGeoServiceProvider>
14#include <QtLocation/QPlaceAttribute>
15#include <QtLocation/QPlaceManager>
16#include <QtLocation/QPlaceDetailsReply>
17#include <QtLocation/QPlaceReply>
18#include <QtLocation/QPlaceIdReply>
19#include <QtLocation/QPlaceContactDetail>
20
22
23/*!
24 \qmltype Place
25 \nativetype QDeclarativePlace
26 \inqmlmodule QtLocation
27 \ingroup qml-QtLocation5-places
28 \ingroup qml-QtLocation5-places-data
29 \since QtLocation 5.5
30
31 \brief The Place type represents a location that is a position of interest.
32
33 The Place type represents a physical location with additional metadata describing that
34 location. Contrasted with \l Location, \l Address, and
35 \l [QtPositioning]{geoCoordinate} type, which are used to describe where a
36 location is.
37 The basic properties of a Place are its \l name and \l location.
38
39 Place objects are typically obtained from a search model and will generally only have their
40 basic properties set. The \l detailsFetched property can be used to test if further property
41 values need to be fetched from the \l Plugin. This can be done by invoking the \l getDetails()
42 method. Progress of the fetching operation can be monitored with the \l status property, which
43 will be set to Place.Fetching when the details are being fetched.
44
45 The Place type has many properties holding information about the location. Details on how to
46 contact the place are available from the \l contactDetails property. Convenience properties
47 for obtaining the primary \l {primaryPhone}{phone}, \l {primaryFax}{fax},
48 \l {primaryEmail}{email} and \l {primaryWebsite}{website} are also available.
49
50 Each place is assigned zero or more \l categories. Categories are typically used when
51 searching for a particular kind of place, such as a restaurant or hotel. Some places have a
52 \l ratings object, which gives an indication of the quality of the place.
53
54 Place metadata is provided by a \l supplier who may require that an \l attribution message be
55 displayed to the user when the place details are viewed.
56
57 Places have an associated \l icon which can be used to represent a place on a map or to
58 decorate a delegate in a view.
59
60 Places may have additional rich content associated with them. The currently supported rich
61 content include editorial descriptions, reviews and images. These are exposed as a set of
62 models for retrieving the content. Editorial descriptions of the place are available from the
63 \l editorialModel property. Reviews of the place are available from the \l reviewModel
64 property. A gallery of pictures of the place can be accessed using the \l imageModel property.
65
66 Places may have additional attributes which are not covered in the formal API. The
67 \l extendedAttributes property provides access to these. The type of extended attributes
68 available is specific to each \l Plugin.
69
70 A Place is almost always tied to a \l plugin. The \l plugin property must be set before it is
71 possible to call \l save(), \l remove() or \l getDetails(). The \l reviewModel, \l imageModel
72 and \l editorialModel are only valid then the \l plugin property is set.
73
74 \section2 Saving a Place
75
76 If the \l Plugin supports it, the Place type can be used to save a place. First create a new
77 Place and set its properties:
78
79 \snippet declarative/places.qml Place savePlace def
80
81 Then invoke the \l save() method:
82
83 \snippet declarative/places.qml Place savePlace
84
85 The \l status property will change to Place.Saving and then to Place.Ready if the save was
86 successful or to Place.Error if an error occurs.
87
88 If the \l placeId property is set, the backend will update an existing place otherwise it will
89 create a new place. On success the \l placeId property will be updated with the identifier of the newly
90 saved place.
91
92 \section3 Caveats
93 \input place-caveats.qdocinc
94
95 \section3 Saving Between Plugins
96 When saving places between plugins, there are a few things to be aware of.
97 Some fields of a place such as the id, categories and icons are plugin specific entities. For example
98 the categories in one manager may not be recognised in another.
99 Therefore trying to save a place directly from one plugin to another is not possible.
100
101 It is generally recommended that saving across plugins be handled as saving \l {Favorites}{favorites}
102 as explained in the Favorites section. However there is another approach which is to create a new place,
103 set its (destination) plugin and then use the \l copyFrom() method to copy the details of the original place.
104 Using \l copyFrom() only copies data that is supported by the destination plugin,
105 plugin specific data such as the place identifier is not copied over. Once the copy is done,
106 the place is in a suitable state to be saved.
107
108 The following snippet provides an example of saving a place to a different plugin
109 using the \l copyFrom method:
110
111 \snippet declarative/places.qml Place save to different plugin
112
113 \section2 Removing a Place
114
115 To remove a place, ensure that a Place object with a valid \l placeId property exists and call
116 its \l remove() method. The \l status property will change to Place.Removing and then to
117 Place.Ready if the save was successful or to Place.Error if an error occurs.
118
119 \section2 Favorites
120 The Places API supports the concept of favorites. Favorites are generally implemented
121 by using two plugins, the first plugin is typically a read-only source of places (origin plugin) and a second
122 read/write plugin (destination plugin) is used to store places from the origin as favorites.
123
124 Each Place has a favorite property which is intended to contain the corresponding place
125 from the destination plugin (the place itself is sourced from the origin plugin). Because both the original
126 place and favorite instances are available, the developer can choose which
127 properties to show to the user. For example the favorite may have a modified name which should
128 be displayed rather than the original name.
129
130 \snippet declarative/places.qml Place favorite
131
132 The following demonstrates how to save a new favorite instance. A call is made
133 to create/initialize the favorite instance and then the instance is saved.
134
135 \snippet declarative/places.qml Place saveFavorite
136
137 The following demonstrates favorite removal:
138
139 \snippet declarative/places.qml Place removeFavorite 1
140 \dots
141 \snippet declarative/places.qml Place removeFavorite 2
142
143 The PlaceSearchModel has a favoritesPlugin property. If the property is set, any places found
144 during a search are checked against the favoritesPlugin to see if there is a corresponding
145 favorite place. If so, the favorite property of the Place is set, otherwise the favorite
146 property is remains null.
147
148 \sa PlaceSearchModel
149*/
150
151QDeclarativePlace::QDeclarativePlace(QObject *parent)
152: QObject(parent),
153 m_extendedAttributes(QQmlPropertyMap::create(this)),
154 m_contactDetails(new QDeclarativeContactDetails(this))
155{
156 connect(m_contactDetails, &QDeclarativeContactDetails::valueChanged,
157 this, &QDeclarativePlace::contactsModified);
158
159 setPlace(QPlace());
160}
161
162QDeclarativePlace::QDeclarativePlace(const QPlace &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent)
163: QObject(parent),
164 m_extendedAttributes(QQmlPropertyMap::create(this)),
165 m_contactDetails(new QDeclarativeContactDetails(this)),
166 m_plugin(plugin)
167{
168 Q_ASSERT(plugin);
169
170 connect(m_contactDetails, &QDeclarativeContactDetails::valueChanged,
171 this, &QDeclarativePlace::contactsModified);
172
173 setPlace(src);
174}
175
176QDeclarativePlace::~QDeclarativePlace()
177{
178}
179
180// From QQmlParserStatus
181void QDeclarativePlace::componentComplete()
182{
183 m_complete = true;
184}
185
186/*!
187 \qmlproperty Plugin Place::plugin
188
189 This property holds the \l Plugin that provided this place which can be used to retrieve more information about the service.
190*/
191void QDeclarativePlace::setPlugin(QDeclarativeGeoServiceProvider *plugin)
192{
193 if (m_plugin == plugin)
194 return;
195
196 m_plugin = plugin;
197 if (m_complete)
198 emit pluginChanged();
199
200 if (m_plugin->isAttached()) {
201 pluginReady();
202 } else {
203 connect(m_plugin, &QDeclarativeGeoServiceProvider::attached,
204 this, &QDeclarativePlace::pluginReady);
205 }
206}
207
208void QDeclarativePlace::pluginReady()
209{
210 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
211 QPlaceManager *placeManager = serviceProvider->placeManager();
212 if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
213 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
214 .arg(m_plugin->name()).arg(serviceProvider->errorString()));
215 return;
216 }
217}
218
219QDeclarativeGeoServiceProvider *QDeclarativePlace::plugin() const
220{
221 return m_plugin;
222}
223
224/*!
225 \qmlproperty ReviewModel Place::reviewModel
226
227 This property holds a model which can be used to retrieve reviews about the place.
228*/
229QDeclarativePlaceReviewModel *QDeclarativePlace::reviewModel()
230{
231 if (!m_reviewModel) {
232 m_reviewModel = new QDeclarativePlaceReviewModel(this);
233 m_reviewModel->setPlace(this);
234 }
235
236 return m_reviewModel;
237}
238
239/*!
240 \qmlproperty ImageModel Place::imageModel
241
242 This property holds a model which can be used to retrieve images of the place.
243*/
244QDeclarativePlaceImageModel *QDeclarativePlace::imageModel()
245{
246 if (!m_imageModel) {
247 m_imageModel = new QDeclarativePlaceImageModel(this);
248 m_imageModel->setPlace(this);
249 }
250
251 return m_imageModel;
252}
253
254/*!
255 \qmlproperty EditorialModel Place::editorialModel
256
257 This property holds a model which can be used to retrieve editorial descriptions of the place.
258*/
259QDeclarativePlaceEditorialModel *QDeclarativePlace::editorialModel()
260{
261 if (!m_editorialModel) {
262 m_editorialModel = new QDeclarativePlaceEditorialModel(this);
263 m_editorialModel->setPlace(this);
264 }
265
266 return m_editorialModel;
267}
268
269/*!
270 \internal
271*/
272void QDeclarativePlace::setPlace(const QPlace &src)
273{
274 QPlace previous = m_src;
275 m_src = src;
276
277 if (previous.categories() != m_src.categories()) {
278 synchronizeCategories();
279 emit categoriesChanged();
280 }
281
282 if (m_location && m_location->parent() == this) {
283 m_location->setLocation(m_src.location());
284 } else if (!m_location || m_location->parent() != this) {
285 m_location = new QDeclarativeGeoLocation(m_src.location(), this);
286 emit locationChanged();
287 }
288
289 if (previous.ratings() != m_src.ratings())
290 emit ratingsChanged();
291 if (previous.supplier() != m_src.supplier())
292 emit supplierChanged();
293 if (previous.icon() != m_src.icon())
294 emit iconChanged();
295 if (previous.name() != m_src.name())
296 emit nameChanged();
297 if (previous.placeId() != m_src.placeId())
298 emit placeIdChanged();
299 if (previous.attribution() != m_src.attribution())
300 emit attributionChanged();
301 if (previous.detailsFetched() != m_src.detailsFetched())
302 emit detailsFetchedChanged();
303 if (previous.primaryPhone() != m_src.primaryPhone())
304 emit primaryPhoneChanged();
305 if (previous.primaryFax() != m_src.primaryFax())
306 emit primaryFaxChanged();
307 if (previous.primaryEmail() != m_src.primaryEmail())
308 emit primaryEmailChanged();
309 if (previous.primaryWebsite() != m_src.primaryWebsite())
310 emit primaryWebsiteChanged();
311
312 if (m_reviewModel && m_src.totalContentCount(QPlaceContent::ReviewType) >= 0) {
313 m_reviewModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ReviewType),
314 m_src.content(QPlaceContent::ReviewType));
315 }
316 if (m_imageModel && m_src.totalContentCount(QPlaceContent::ImageType) >= 0) {
317 m_imageModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ImageType),
318 m_src.content(QPlaceContent::ImageType));
319 }
320 if (m_editorialModel && m_src.totalContentCount(QPlaceContent::EditorialType) >= 0) {
321 m_editorialModel->initializeCollection(m_src.totalContentCount(QPlaceContent::EditorialType),
322 m_src.content(QPlaceContent::EditorialType));
323 }
324
325 pullExtendedAttributes();
326 synchronizeContacts();
327}
328
329QPlace QDeclarativePlace::place() const
330{
331 // The properties handled explicirly here are not stored in m_src, but
332 // but are instead stored in QDeclarative* objects which we need to update
333 // explicitly.
334
335 QPlace result = m_src;
336
337 // Categories
338 QList<QPlaceCategory> categories;
339 for (QDeclarativeCategory *value : std::as_const(m_categories))
340 categories.append(value->category());
341
342 result.setCategories(categories);
343
344 // Location
345 result.setLocation(m_location ? m_location->location() : QGeoLocation());
346
347 //contact details
348 QList<QPlaceContactDetail> cppDetails;
349 for (const QString &key : m_contactDetails->keys()) {
350 cppDetails.clear();
351 if (m_contactDetails->value(key).typeId() == QMetaType::QVariantList) {
352 const QVariantList detailsVarList = m_contactDetails->value(key).toList();
353 for (const QVariant &detailVar : detailsVarList)
354 cppDetails.append(detailVar.value<QPlaceContactDetail>());
355 } else {
356 cppDetails.append(m_contactDetails->value(key).value<QPlaceContactDetail>());
357 }
358 result.setContactDetails(key, cppDetails);
359 }
360
361 return result;
362}
363
364/*!
365 \qmlproperty QtPositioning::Location Place::location
366
367 This property holds the location of the place which can be used to retrieve the coordinate,
368 address and the bounding box.
369*/
370void QDeclarativePlace::setLocation(QDeclarativeGeoLocation *location)
371{
372 if (m_location == location)
373 return;
374
375 if (m_location && m_location->parent() == this)
376 delete m_location;
377
378 m_location = location;
379 emit locationChanged();
380}
381
382QDeclarativeGeoLocation *QDeclarativePlace::location() const
383{
384 return m_location;
385}
386
387/*!
388 \qmlproperty Ratings Place::ratings
389
390 This property holds ratings of the place. The ratings provide an indication of the quality of a
391 place.
392*/
393void QDeclarativePlace::setRatings(const QPlaceRatings &rating)
394{
395 if (m_src.ratings() != rating) {
396 m_src.setRatings(rating);
397 emit ratingsChanged();
398 }
399}
400
401QPlaceRatings QDeclarativePlace::ratings() const
402{
403 return m_src.ratings();
404}
405
406/*!
407 \qmlproperty Supplier Place::supplier
408
409 This property holds the supplier of the place data.
410 The supplier is typically a business or organization that collected the data about the place.
411*/
412void QDeclarativePlace::setSupplier(const QPlaceSupplier &supplier)
413{
414 if (m_src.supplier() != supplier) {
415 m_src.setSupplier(supplier);
416 emit supplierChanged();
417 }
418}
419
420QPlaceSupplier QDeclarativePlace::supplier() const
421{
422 return m_src.supplier();
423}
424
425/*!
426 \qmlproperty Icon Place::icon
427
428 This property holds a graphical icon which can be used to represent the place.
429*/
430QPlaceIcon QDeclarativePlace::icon() const
431{
432 return m_src.icon();
433}
434
435void QDeclarativePlace::setIcon(const QPlaceIcon &icon)
436{
437 if (m_src.icon() != icon) {
438 m_src.setIcon(icon);
439 emit iconChanged();
440 }
441}
442
443/*!
444 \qmlproperty string Place::name
445
446 This property holds the name of the place which can be used to represent the place.
447*/
448void QDeclarativePlace::setName(const QString &name)
449{
450 if (m_src.name() != name) {
451 m_src.setName(name);
452 emit nameChanged();
453 }
454}
455
456QString QDeclarativePlace::name() const
457{
458 return m_src.name();
459}
460
461/*!
462 \qmlproperty string Place::placeId
463
464 This property holds the unique identifier of the place. The place identifier is only meaningful to the
465 \l Plugin that generated it and is not transferable between \l {Plugin}{Plugins}. The place id
466 is not guaranteed to be universally unique, but unique within the \l Plugin that generated it.
467
468 If only the place identifier is known, all other place data can fetched from the \l Plugin.
469
470 \snippet declarative/places.qml Place placeId
471*/
472void QDeclarativePlace::setPlaceId(const QString &placeId)
473{
474 if (m_src.placeId() != placeId) {
475 m_src.setPlaceId(placeId);
476 emit placeIdChanged();
477 }
478}
479
480QString QDeclarativePlace::placeId() const
481{
482 return m_src.placeId();
483}
484
485/*!
486 \qmlproperty string Place::attribution
487
488 This property holds a rich text attribution string for the place.
489 Some providers may require that the attribution be shown to the user
490 whenever a place is displayed. The contents of this property should
491 be shown to the user if it is not empty.
492*/
493void QDeclarativePlace::setAttribution(const QString &attribution)
494{
495 if (m_src.attribution() != attribution) {
496 m_src.setAttribution(attribution);
497 emit attributionChanged();
498 }
499}
500
501QString QDeclarativePlace::attribution() const
502{
503 return m_src.attribution();
504}
505
506/*!
507 \qmlproperty bool Place::detailsFetched
508
509 This property indicates whether the details of the place have been fetched. If this property
510 is false, the place details have not yet been fetched. Fetching can be done by invoking the
511 \l getDetails() method.
512
513 \sa getDetails()
514*/
515bool QDeclarativePlace::detailsFetched() const
516{
517 return m_src.detailsFetched();
518}
519
520/*!
521 \qmlproperty enumeration Place::status
522
523 This property holds the status of the place. It can be one of:
524
525 \table
526 \row
527 \li Place.Ready
528 \li No error occurred during the last operation, further operations may be performed on
529 the place.
530 \row
531 \li Place.Saving
532 \li The place is currently being saved, no other operation may be performed until
533 complete.
534 \row
535 \li Place.Fetching
536 \li The place details are currently being fetched, no other operations may be performed
537 until complete.
538 \row
539 \li Place.Removing
540 \li The place is currently being removed, no other operations can be performed until
541 complete.
542 \row
543 \li Place.Error
544 \li An error occurred during the last operation, further operations can still be
545 performed on the place.
546 \endtable
547
548 The status of a place can be checked by connecting the status property
549 to a handler function, and then have the handler function process the change
550 in status.
551
552 \snippet declarative/places.qml Place checkStatus
553 \dots
554 \snippet declarative/places.qml Place checkStatus handler
555
556*/
557void QDeclarativePlace::setStatus(Status status, const QString &errorString)
558{
559 Status originalStatus = m_status;
560 m_status = status;
561 m_errorString = errorString;
562
563 if (originalStatus != m_status)
564 emit statusChanged();
565}
566
567QDeclarativePlace::Status QDeclarativePlace::status() const
568{
569 return m_status;
570}
571
572/*!
573 \internal
574*/
575void QDeclarativePlace::finished()
576{
577 if (!m_reply)
578 return;
579
580 if (m_reply->error() == QPlaceReply::NoError) {
581 switch (m_reply->type()) {
582 case (QPlaceReply::IdReply) : {
583 QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(m_reply);
584
585 switch (idReply->operationType()) {
586 case QPlaceIdReply::SavePlace:
587 setPlaceId(idReply->id());
588 break;
589 case QPlaceIdReply::RemovePlace:
590 break;
591 default:
592 //Other operation types shouldn't ever be received.
593 break;
594 }
595 break;
596 }
597 case (QPlaceReply::DetailsReply): {
598 QPlaceDetailsReply *detailsReply = qobject_cast<QPlaceDetailsReply *>(m_reply);
599 setPlace(detailsReply->place());
600 break;
601 }
602 default:
603 //other types of replies shouldn't ever be received.
604 break;
605 }
606
607 m_errorString.clear();
608
609 m_reply->deleteLater();
610 m_reply = nullptr;
611
612 setStatus(QDeclarativePlace::Ready);
613 } else {
614 QString errorString = m_reply->errorString();
615
616 m_reply->deleteLater();
617 m_reply = nullptr;
618
619 setStatus(QDeclarativePlace::Error, errorString);
620 }
621}
622
623/*!
624 \internal
625*/
626void QDeclarativePlace::contactsModified(const QString &key, const QVariant &)
627{
628 primarySignalsEmission(key);
629}
630
631/*!
632 \internal
633*/
634void QDeclarativePlace::cleanupDeletedCategories()
635{
636 for (QDeclarativeCategory * category : m_categoriesToBeDeleted) {
637 if (category->parent() == this)
638 delete category;
639 }
640 m_categoriesToBeDeleted.clear();
641}
642
643/*!
644 \qmlmethod void Place::getDetails()
645
646 This method starts fetching place details.
647
648 The \l status property will change to Place.Fetching while the fetch is in progress. On
649 success the object's properties will be updated, \l status will be set to Place.Ready and
650 \l detailsFetched will be set to true. On error \l status will be set to Place.Error. The
651 \l errorString() method can be used to get the details of the error.
652*/
653void QDeclarativePlace::getDetails()
654{
655 QPlaceManager *placeManager = manager();
656 if (!placeManager)
657 return;
658
659 m_reply = placeManager->getPlaceDetails(placeId());
660 connect(m_reply, &QPlaceReply::finished, this, &QDeclarativePlace::finished);
661 setStatus(QDeclarativePlace::Fetching);
662}
663
664/*!
665 \qmlmethod void Place::save()
666
667 This method performs a save operation on the place.
668
669 The \l status property will change to Place.Saving while the save operation is in progress. On
670 success the \l status will be set to Place.Ready. On error \l status will be set to Place.Error.
671 The \l errorString() method can be used to get the details of the error.
672
673 If the \l placeId property was previously empty, it will be assigned a valid value automatically
674 during a successful save operation.
675
676 Note that a \l PlaceSearchModel will call Place::getDetails on any place that it detects an update
677 on. A consequence of this is that whenever a Place from a \l PlaceSearchModel is successfully saved,
678 it will be followed by a fetch of place details, leading to a sequence of state changes
679 of \c Saving, \c Ready, \c Fetching, \c Ready.
680
681*/
682void QDeclarativePlace::save()
683{
684 QPlaceManager *placeManager = manager();
685 if (!placeManager)
686 return;
687
688 m_reply = placeManager->savePlace(place());
689 connect(m_reply, &QPlaceReply::finished, this, &QDeclarativePlace::finished);
690 setStatus(QDeclarativePlace::Saving);
691}
692
693/*!
694 \qmlmethod void Place::remove()
695
696 This method performs a remove operation on the place.
697
698 The \l status property will change to Place.Removing while the save operation is in progress.
699 On success \l status will be set to Place.Ready. On error \l status will be set to
700 Place.Error. The \l errorString() method can be used to get the details of the error.
701*/
702void QDeclarativePlace::remove()
703{
704 QPlaceManager *placeManager = manager();
705 if (!placeManager)
706 return;
707
708 m_reply = placeManager->removePlace(place().placeId());
709 connect(m_reply, &QPlaceReply::finished, this, &QDeclarativePlace::finished);
710 setStatus(QDeclarativePlace::Removing);
711}
712
713/*!
714 \qmlmethod string Place::errorString()
715
716 Returns a string description of the error of the last operation. If the last operation
717 completed successfully then the string is empty.
718*/
719QString QDeclarativePlace::errorString() const
720{
721 return m_errorString;
722}
723
724/*!
725 \qmlproperty string Place::primaryPhone
726
727 This property holds the primary phone number of the place. If no "phone" contact detail is
728 defined for this place, this property will be an empty string. It is equivalent to:
729
730
731 \snippet declarative/places.qml Place primaryPhone
732*/
733QString QDeclarativePlace::primaryPhone() const
734{
735 return primaryValue(QPlaceContactDetail::Phone);
736}
737
738/*!
739 \qmlproperty string Place::primaryFax
740
741 This property holds the primary fax number of the place. If no "fax" contact detail is
742 defined for this place this property will be an empty string. It is equivalent to
743
744 \snippet declarative/places.qml Place primaryFax
745*/
746QString QDeclarativePlace::primaryFax() const
747{
748 return primaryValue(QPlaceContactDetail::Fax);
749}
750
751/*!
752 \qmlproperty string Place::primaryEmail
753
754 This property holds the primary email address of the place. If no "email" contact detail is
755 defined for this place this property will be an empty string. It is equivalent to
756
757 \snippet declarative/places.qml Place primaryEmail
758*/
759QString QDeclarativePlace::primaryEmail() const
760{
761 return primaryValue(QPlaceContactDetail::Email);
762}
763
764/*!
765 \qmlproperty string Place::primaryWebsite
766
767 This property holds the primary website url of the place. If no "website" contact detail is
768 defined for this place this property will be an empty string. It is equivalent to
769
770 \snippet declarative/places.qml Place primaryWebsite
771*/
772
773QUrl QDeclarativePlace::primaryWebsite() const
774{
775 return QUrl(primaryValue(QPlaceContactDetail::Website));
776}
777
778/*!
779 \qmlproperty ExtendedAttributes Place::extendedAttributes
780
781 This property holds the extended attributes of a place. Extended attributes are additional
782 information about a place not covered by the place's properties.
783*/
784QQmlPropertyMap *QDeclarativePlace::extendedAttributes() const
785{
786 return m_extendedAttributes;
787}
788
789/*!
790 \qmlproperty ContactDetails Place::contactDetails
791
792 This property holds the contact information for this place, for example a phone number or
793 a website URL. This property is a map of \l contactDetail objects.
794*/
795QDeclarativeContactDetails *QDeclarativePlace::contactDetails() const
796{
797 return m_contactDetails;
798}
799
800/*!
801 \qmlproperty list<Category> Place::categories
802
803 This property holds the list of categories this place is a member of. The categories that can
804 be assigned to a place are specific to each \l plugin.
805*/
806QQmlListProperty<QDeclarativeCategory> QDeclarativePlace::categories()
807{
808 return QQmlListProperty<QDeclarativeCategory>(this,
809 0, // opaque data parameter
810 category_append,
811 category_count,
812 category_at,
813 category_clear);
814}
815
816/*!
817 \internal
818*/
819void QDeclarativePlace::category_append(QQmlListProperty<QDeclarativeCategory> *prop,
820 QDeclarativeCategory *value)
821{
822 QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
823
824 if (object->m_categoriesToBeDeleted.contains(value))
825 object->m_categoriesToBeDeleted.removeAll(value);
826
827 if (!object->m_categories.contains(value)) {
828 object->m_categories.append(value);
829 QList<QPlaceCategory> list = object->m_src.categories();
830 list.append(value->category());
831 object->m_src.setCategories(list);
832
833 emit object->categoriesChanged();
834 }
835}
836
837/*!
838 \internal
839*/
840qsizetype QDeclarativePlace::category_count(QQmlListProperty<QDeclarativeCategory> *prop)
841{
842 return static_cast<QDeclarativePlace *>(prop->object)->m_categories.count();
843}
844
845/*!
846 \internal
847*/
848QDeclarativeCategory *QDeclarativePlace::category_at(QQmlListProperty<QDeclarativeCategory> *prop,
849 qsizetype index)
850{
851 QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
852 QDeclarativeCategory *res = NULL;
853 if (object->m_categories.count() > index && index > -1) {
854 res = object->m_categories[index];
855 }
856 return res;
857}
858
859/*!
860 \internal
861*/
862void QDeclarativePlace::category_clear(QQmlListProperty<QDeclarativeCategory> *prop)
863{
864 QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object);
865 if (object->m_categories.isEmpty())
866 return;
867
868 for (auto *category : std::as_const(object->m_categories)) {
869 if (category->parent() == object)
870 object->m_categoriesToBeDeleted.append(category);
871 }
872
873 object->m_categories.clear();
874 object->m_src.setCategories(QList<QPlaceCategory>());
875 emit object->categoriesChanged();
876 QMetaObject::invokeMethod(object, "cleanupDeletedCategories", Qt::QueuedConnection);
877}
878
879/*!
880 \internal
881*/
882void QDeclarativePlace::synchronizeCategories()
883{
884 qDeleteAll(m_categories);
885 m_categories.clear();
886 for (const QPlaceCategory &value : m_src.categories()) {
887 QDeclarativeCategory *declarativeValue = new QDeclarativeCategory(value, m_plugin, this);
888 m_categories.append(declarativeValue);
889 }
890}
891
892/*!
893 \qmlproperty enumeration Place::visibility
894
895 This property holds the visibility of the place. It can be one of:
896
897 \table
898 \row
899 \li Place.UnspecifiedVisibility
900 \li The visibility of the place is unspecified, the default visibility of the \l Plugin
901 will be used.
902 \row
903 \li Place.DeviceVisibility
904 \li The place is limited to the current device. The place will not be transferred off
905 of the device.
906 \row
907 \li Place.PrivateVisibility
908 \li The place is private to the current user. The place may be transferred to an online
909 service but is only ever visible to the current user.
910 \row
911 \li Place.PublicVisibility
912 \li The place is public.
913 \endtable
914
915 Note that visibility does not affect how the place is displayed
916 in the user-interface of an application on the device. Instead,
917 it defines the sharing semantics of the place.
918*/
919QDeclarativePlace::Visibility QDeclarativePlace::visibility() const
920{
921 return static_cast<QDeclarativePlace::Visibility>(m_src.visibility());
922}
923
924void QDeclarativePlace::setVisibility(Visibility visibility)
925{
926 if (static_cast<QDeclarativePlace::Visibility>(m_src.visibility()) == visibility)
927 return;
928
929 m_src.setVisibility(static_cast<QLocation::Visibility>(visibility));
930 emit visibilityChanged();
931}
932
933/*!
934 \qmlproperty Place Place::favorite
935
936 This property holds the favorite instance of a place.
937*/
938QDeclarativePlace *QDeclarativePlace::favorite() const
939{
940 return m_favorite;
941}
942
943void QDeclarativePlace::setFavorite(QDeclarativePlace *favorite)
944{
945
946 if (m_favorite == favorite)
947 return;
948
949 if (m_favorite && m_favorite->parent() == this)
950 delete m_favorite;
951
952 m_favorite = favorite;
953 emit favoriteChanged();
954}
955
956/*!
957 \qmlmethod void Place::copyFrom(Place original)
958
959 Copies data from an \a original place into this place. Only data that is supported by this
960 place's plugin is copied over and plugin specific data such as place identifier is not copied over.
961*/
962void QDeclarativePlace::copyFrom(QDeclarativePlace *original)
963{
964 QPlaceManager *placeManager = manager();
965 if (!placeManager)
966 return;
967
968 setPlace(placeManager->compatiblePlace(original->place()));
969}
970
971/*!
972 \qmlmethod void Place::initializeFavorite(Plugin destinationPlugin)
973
974 Creates a favorite instance for the place which is to be saved into the
975 destination plugin \a destinationPlugin. This method does nothing if the
976 favorite property is not \c null.
977*/
978void QDeclarativePlace::initializeFavorite(QDeclarativeGeoServiceProvider *plugin)
979{
980 if (m_favorite == 0) {
981 QDeclarativePlace *place = new QDeclarativePlace(this);
982 place->setPlugin(plugin);
983 place->copyFrom(this);
984 setFavorite(place);
985 }
986}
987
988/*!
989 \internal
990*/
991void QDeclarativePlace::pullExtendedAttributes()
992{
993 const QStringList keys = m_extendedAttributes->keys();
994 for (const QString &key : keys)
995 m_extendedAttributes->clear(key);
996
997 const QStringList attributeTypes = m_src.extendedAttributeTypes();
998 for (const QString &attributeType : attributeTypes) {
999 m_extendedAttributes->insert(attributeType,
1000 QVariant::fromValue(m_src.extendedAttribute(attributeType)));
1001 }
1002
1003 emit extendedAttributesChanged();
1004}
1005
1006/*!
1007 \internal
1008*/
1009void QDeclarativePlace::synchronizeContacts()
1010{
1011 //clear out contact data
1012 for (const QString &contactType : m_contactDetails->keys()) {
1013 const QList<QVariant> contacts = m_contactDetails->value(contactType).toList();
1014 for (const QVariant &var : contacts) {
1015 QObject *obj = var.value<QObject *>();
1016 if (obj->parent() == this)
1017 delete obj;
1018 }
1019 m_contactDetails->insert(contactType, QVariantList());
1020 }
1021
1022 //insert new contact data from source place
1023 for (const QString &contactType : m_src.contactTypes()) {
1024 const QList<QPlaceContactDetail> sourceContacts = m_src.contactDetails(contactType);
1025 QVariantList declContacts;
1026 for (const QPlaceContactDetail &sourceContact : sourceContacts)
1027 declContacts.append(QVariant::fromValue(sourceContact));
1028 m_contactDetails->insert(contactType, declContacts);
1029 }
1030 primarySignalsEmission();
1031}
1032
1033/*!
1034 \internal
1035 Helper function to emit the signals for the primary___()
1036 fields. It is expected that the values of the primary___()
1037 functions have already been modified to new values.
1038*/
1039void QDeclarativePlace::primarySignalsEmission(const QString &type)
1040{
1041 if (type.isEmpty() || type == QPlaceContactDetail::Phone) {
1042 if (m_prevPrimaryPhone != primaryPhone()) {
1043 m_prevPrimaryPhone = primaryPhone();
1044 emit primaryPhoneChanged();
1045 }
1046 if (!type.isEmpty())
1047 return;
1048 }
1049
1050 if (type.isEmpty() || type == QPlaceContactDetail::Email) {
1051 if (m_prevPrimaryEmail != primaryEmail()) {
1052 m_prevPrimaryEmail = primaryEmail();
1053 emit primaryEmailChanged();
1054 }
1055 if (!type.isEmpty())
1056 return;
1057 }
1058
1059 if (type.isEmpty() || type == QPlaceContactDetail::Website) {
1060 if (m_prevPrimaryWebsite != primaryWebsite()) {
1061 m_prevPrimaryWebsite = primaryWebsite();
1062 emit primaryWebsiteChanged();
1063 }
1064 if (!type.isEmpty())
1065 return;
1066 }
1067
1068 if (type.isEmpty() || type == QPlaceContactDetail::Fax) {
1069 if (m_prevPrimaryFax != primaryFax()) {
1070 m_prevPrimaryFax = primaryFax();
1071 emit primaryFaxChanged();
1072 }
1073 }
1074}
1075
1076/*!
1077 \internal
1078 Helper function to return the manager, this manager is intended to be used
1079 to perform the next operation. If a an operation is currently underway
1080 then return a null pointer.
1081*/
1082QPlaceManager *QDeclarativePlace::manager()
1083{
1084 if (m_status != QDeclarativePlace::Ready && m_status != QDeclarativePlace::Error)
1085 return nullptr;
1086
1087 if (m_reply) {
1088 m_reply->abort();
1089 m_reply->deleteLater();
1090 m_reply = nullptr;
1091 }
1092
1093 if (!m_plugin) {
1094 qmlWarning(this) << QStringLiteral("Plugin is not assigned to place.");
1095 return nullptr;
1096 }
1097
1098 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
1099 if (!serviceProvider)
1100 return nullptr;
1101
1102 QPlaceManager *placeManager = serviceProvider->placeManager();
1103
1104 if (!placeManager) {
1105 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
1106 .arg(m_plugin->name()).arg(serviceProvider->errorString()));
1107 return nullptr;
1108 }
1109
1110 return placeManager;
1111}
1112
1113/*!
1114 \internal
1115*/
1116QString QDeclarativePlace::primaryValue(const QString &contactType) const
1117{
1118 QVariant value = m_contactDetails->value(contactType);
1119 if (value.userType() == qMetaTypeId<QJSValue>())
1120 value = value.value<QJSValue>().toVariant();
1121
1122 if (value.userType() == QMetaType::QVariantList) {
1123 QVariantList detailList = m_contactDetails->value(contactType).toList();
1124 if (!detailList.isEmpty())
1125 return detailList.at(0).value<QPlaceContactDetail>().value();
1126 } else if (value.metaType() == QMetaType::fromType<QPlaceContactDetail>()) {
1127 return value.value<QPlaceContactDetail>().value();
1128 }
1129
1130 return QString();
1131}
1132
1133QT_END_NAMESPACE
Combined button and popup list for selecting options.