1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 **   * Redistributions of source code must retain the above copyright
25 **     notice, this list of conditions and the following disclaimer.
26 **   * Redistributions in binary form must reproduce the above copyright
27 **     notice, this list of conditions and the following disclaimer in
28 **     the documentation and/or other materials provided with the
29 **     distribution.
30 **   * Neither the name of The Qt Company Ltd nor the names of its
31 **     contributors may be used to endorse or promote products derived
32 **     from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50 
51 #include <QDebug>
52 #include <QGeoCircle>
53 #include <QGeoServiceProvider>
54 #include <QPlaceDetailsReply>
55 #include <QPlaceIdReply>
56 #include <QPlaceManager>
57 #include <QPlaceSearchReply>
58 #include <QPlaceResult>
59 #include <QPlaceImage>
60 #include <QtCore/QMetaObject>
61 
62 class RequestHandler : public QObject
63 {
64 public:
initializeManager()65     void initializeManager() {
66         //! [Initialize Manager]
67         //The "provider name" is used to select a particular provider
68         QGeoServiceProvider *provider = new QGeoServiceProvider("provider name");
69         QPlaceManager *manager = provider->placeManager();
70         //! [Initialize Manager]
71         Q_UNUSED(provider);
72         Q_UNUSED(manager);
73     }
74 
simpleSearch()75     void simpleSearch()
76     {
77         //! [Simple search]
78         //1) Make an appropriate request
79         QPlaceSearchRequest searchRequest;
80         searchRequest.setSearchTerm("ice cream");
81         searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(12.34, 56.78)));
82 
83         //2) Use the manager to initiate a request and retrieve a reply object
84         QPlaceSearchReply * searchReply = manager->search(searchRequest);
85 
86         //3) Connect the reply object to a slot which is invoked upon operation completion
87         connect(searchReply, SIGNAL(finished()), this, SLOT(processSearchReply()));
88         //! [Simple search]
89     }
90 
search()91     void search()
92     {
93         //! [Search for places cpp]
94 
95         //instantiate request and set parameters
96         QPlaceSearchRequest searchRequest;
97         searchRequest.setSearchTerm("ice cream");
98         searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(12.34, 56.78)));
99 
100         //send off a search request
101         /*QPlaceSearchReply * */ searchReply = manager->search(searchRequest);
102 
103         //connect a slot to handle the reply
104         connect(searchReply, SIGNAL(finished()), this, SLOT(handleSearchReply()));
105 
106         //! [Search for places cpp]
107     }
108 
searchPaging()109     void searchPaging()
110     {
111         //! [Search paging]
112         QPlaceSearchRequest searchRequest;
113         searchRequest.setLimit(15); //specify how many results are to be retrieved.
114         //! [Search paging]
115     }
116 
details()117     void details()
118     {
119         QPlace place;
120         //! [Details check]
121         if (!place.detailsFetched()) {
122             /*QPlaceDetailsReply * */ detailsReply = manager->getPlaceDetails(place.placeId());
123             connect(detailsReply, SIGNAL(finished()), this, SLOT(handleDetailsReply()));
124         }
125         //! [Details check]
126     }
127 
images()128     void images()
129     {
130         QPlace place;
131 
132         //! [Image request]
133         QPlaceContentRequest request;
134         request.setContentType(QPlaceContent::ImageType);
135         request.setPlaceId(place.placeId());
136         request.setLimit(5);
137         /*QPlaceContentReply * */ contentReply = manager->getPlaceContent(request);
138         connect(contentReply, SIGNAL(finished()), this, SLOT(handleImagesReply()));
139         //! [Image request]
140     }
141 
142 
suggestion()143     void suggestion()
144     {
145         //! [Suggestion request]
146         QPlaceSearchRequest request;
147         request.setSearchTerm("piz");
148         request.setSearchArea(QGeoCircle(QGeoCoordinate(12.34, 56.78)));
149         /* QPlaceSearchSuggestion * */suggestionReply = manager->searchSuggestions(request);
150         connect(suggestionReply, SIGNAL(finished()), this, SLOT(handleSuggestionReply()));
151         //! [Suggestion request]
152     }
153 
savePlace()154     void savePlace()
155     {
156         //! [Save place pt1]
157         QPlace  place;
158         place.setName( "Fred's Ice Cream Parlor" );
159 
160         QGeoLocation location;
161         location.setCoordinate(QGeoCoordinate(12.34, 56.78));
162 
163         QGeoAddress address;
164         address.setStreet("111 Nother Street");
165         //! [Save place pt1]
166 
167         //! [Save place pt2]
168         location.setAddress(address);
169         place.setLocation(location);
170 
171         /* QPlaceIdReply * */savePlaceReply = manager->savePlace(place);
172         connect(savePlaceReply, SIGNAL(finished()), this, SLOT(handleSavePlaceReply()));
173         //! [Save place pt2]
174     }
175 
removePlace()176     void removePlace()
177     {
178         QPlace place;
179         //! [Remove place]
180         /* QPlaceIdReply * */removePlaceReply = manager->removePlace(place.placeId());
181         connect(removePlaceReply, SIGNAL(finished()), this, SLOT(handleRemovePlaceReply()));
182         //! [Remove place]
183     }
184 
initializeCategories()185     void initializeCategories()
186     {
187         //! [Initialize categories]
188         /* QPlaceReply * */initCatReply = manager->initializeCategories();
189         connect(initCatReply, SIGNAL(finished()), this, SLOT(handleInitCatReply()));
190         //! [Initialize categories]
191     }
192 
saveCategory()193     void saveCategory()
194     {
195         //! [Save category]
196         QPlaceCategory fastFood;
197 
198         QPlaceCategory category;
199         category.setName("pizza");
200         /*QPlaceIdReply */ saveCategoryReply = manager->saveCategory(category);
201         connect(saveCategoryReply, SIGNAL(finished()), this, SLOT(handleSaveCategoryReply()));
202 
203         //we could have saved a category as a child by supplying a parent identifier.
204         saveCategoryReply = manager->saveCategory(category, fastFood.categoryId());
205         //! [Save category]
206     }
207 
removeCategory()208     void removeCategory()
209     {
210         QPlaceCategory category;
211         //! [Remove category]
212         /* QPlaceIdReply * */removeCategoryReply = manager->removeCategory(place.placeId());
213         connect(removeCategoryReply, SIGNAL(finished()), this, SLOT(handleRemoveCategoryReply()));
214         //! [Remove category]
215     }
216 
searchRequest()217     void searchRequest() {
218         QPlaceCategory diner;
219         QPlaceCategory restaurant;
220 
221         //! [Search request]
222         QPlaceSearchRequest searchRequest;
223         searchRequest.setSearchTerm("Fast food"); //search term for what we are interested in
224 
225         //set a search center
226         searchRequest.setSearchArea(QGeoCircle(QGeoCoordinate(2.3, 48.87)));
227 
228         //set a distance hint as a relevancy hint.
229         //closer places have greater weighting in the ranking of results.
230         searchRequest.setRelevanceHint(QPlaceSearchRequest::DistanceHint);
231 
232         //use limit to adjust pagination.
233         //this limits the number of place results to 5 per page.
234         searchRequest.setLimit(5);
235 
236         //provide some categories to narrow down search
237         QList<QPlaceCategory> categories;
238         categories << diner << restaurant;
239         searchRequest.setCategories(categories);
240         //! [Search request]
241     }
242 
content()243     void content() {
244         QPlace place;
245         //! [Content request]
246         QPlaceContentRequest request;
247         request.setContentType(QPlaceContent::ImageType);
248         request.setPlaceId(place.placeId());
249         request.setLimit(5);
250 
251         QPlaceContentReply *contentReply = manager->getPlaceContent(request);
252         //..connect signals..//
253 
254         //! [Content request]
255         Q_UNUSED(contentReply);
256     }
257 
contentConversion()258     void contentConversion()
259     {
260         //! [Content conversion]
261         QPlaceImage image;
262         image.setUrl(QUrl("www.example.com"));
263 
264         QPlaceContent content = image;
265 
266         QPlaceImage image2;
267         image2 = content;
268         qDebug() << image2.url(); //image2.url() == "www.example.com"
269         //! [Content conversion]
270     }
271 
icon()272     void icon() {
273         QPlace place;
274         //! [icon]
275         QUrl iconSourceUrl = place.icon().url(QSize(32,32));
276 
277         //A default icon may also be requested like so
278         iconSourceUrl = place.icon().url();
279         //! [icon]
280     }
281 
saveBetweenManagers()282     void saveBetweenManagers()  {
283         QPlaceResult result;
284         QPlaceIdReply *saveReply;
285         //! [ Save to different manager]
286         //result retrieved from a different manager)
287         QPlace place = manager->compatiblePlace(result.place());
288         saveReply = manager->savePlace(place);
289         //! [ Save to different manager]
290         saveReply->abort();//needed to avoid warnings
291     }
292 
ratings()293     void ratings() {
294         //! [Ratings]
295         qDebug() << QString("This place rated ") + place.ratings().average()
296                     + "out of " + place.ratings().maximum() + "stars";
297         //! [Ratings]
298     }
299 
matchPlaces()300     void matchPlaces() {
301         QList<QPlaceSearchResult> results;
302         //! [Match places]
303         QPlaceMatchRequest request;
304         request.setResults(results);
305         QVariantMap parameters;
306         parameters.insert(QPlaceMatchRequest::AlternativeId, "x_id_here");
307         request.setParameters(parameters);
308         matchReply = manager->matchingPlaces(request);
309         //! [Match places]
310     }
311 
312 public slots:
313     // ![Simple search handler]
314     //4) Have the slot appropriately process the results of the operation
processSearchReply()315     void processSearchReply() {
316         if (searchReply->error() == QPlaceReply::NoError) {
317             foreach (const QPlaceSearchResult &result, searchReply->results()) {
318                 if (result.type() == QPlaceSearchResult::PlaceResult)
319                     qDebug() << "Title:" << result.title();
320             }
321         }
322 
323     //5) Discard the rely object when done.
324         searchReply->deleteLater();
325         searchReply = 0;
326     }
327     // ![Simple search handler]
328 
329     //! [Search for places handler cpp]
handleSearchReply()330     void handleSearchReply() {
331         if (searchReply->error() == QPlaceReply::NoError) {
332             foreach (const QPlaceSearchResult &result, searchReply->results()) {
333                 if (result.type() == QPlaceSearchResult::PlaceResult) {
334                     QPlaceResult placeResult = result;
335                     qDebug() << "Name: " << placeResult.place().name();
336                     qDebug() << "Coordinate " << placeResult.place().location().coordinate().toString();
337                     qDebug() << "Street: " << placeResult.place().location().address().street();
338                     qDebug() << "Distance: " << placeResult.distance();
339                 }
340             }
341         }
342         searchReply->deleteLater();  //discard reply
343         searchReply = 0;
344     }
345     //! [Search for places handler cpp]
346 
347     //! [Details handler cpp]
handleDetailsReply()348     void handleDetailsReply() {
349         QPlace place;
350         if (detailsReply->error() == QPlaceReply::NoError)
351             place = detailsReply->place();
352 
353         detailsReply->deleteLater(); //discard reply
354         detailsReply = 0;
355     }
356     //! [Details handler cpp]
357 
358     //! [Image handler]
handleImagesReply()359     void handleImagesReply() {
360         if (contentReply->error() == QPlaceReply::NoError) {
361             const auto content = contentReply->content();
362             for (auto iter = content.cbegin(), end = content.cend(); iter != end; ++iter) {
363                 qDebug() << "Index: " << iter.key();
364                 QPlaceImage image = iter.value();
365                 qDebug() << image.url();
366                 qDebug() << image.mimeType();
367             }
368 
369             //alternatively if indexes are irrelevant
370             foreach (const QPlaceImage &image, contentReply->content()) {
371                 qDebug() << image.url();
372                 qDebug() << image.mimeType();
373             }
374 
375             //we can assign content to the place that it belongs to.
376             //the place object serves as a container where we can retrieve
377             //content that has already been fetched
378             place.insertContent(contentReply->request().contentType(), contentReply->content());
379             place.setTotalContentCount(contentReply->request().contentType(), contentReply->totalCount());
380         }
381 
382         contentReply->deleteLater();
383         contentReply = 0;
384     }
385     //! [Image handler]
386 
387     //! [Suggestion handler]
handleSuggestionReply()388     void handleSuggestionReply() {
389         if (suggestionReply->error() == QPlaceReply::NoError) {
390             foreach (const QString &suggestion, suggestionReply->suggestions())
391                 qDebug() << suggestion;
392         }
393 
394         suggestionReply->deleteLater(); //discard reply
395         suggestionReply = 0;
396     }
397 
398     //! [Suggestion handler]
399 
400     //! [Save place handler]
handleSavePlaceReply()401     void handleSavePlaceReply() {
402         if (savePlaceReply->error() == QPlaceReply::NoError)
403             qDebug() << savePlaceReply->id();
404 
405         savePlaceReply->deleteLater(); //discard reply
406         savePlaceReply = 0;
407     }
408     //! [Save place handler]
409 
410     //! [Remove place handler]
handleRemovePlaceReply()411     void handleRemovePlaceReply() {
412         if (removePlaceReply->error() == QPlaceReply::NoError)
413             qDebug() << "Removal of place identified by"
414                      << removePlaceReply->id() << "was successful";
415 
416         removePlaceReply->deleteLater(); //discard reply
417         removePlaceReply = 0;
418     }
419     //! [Remove place handler]
420 
421     //! [Initialize categories reply]
handleInitCatReply()422     void handleInitCatReply() {
423         if (initCatReply->error() == QPlaceReply::NoError)
424             qDebug() << "Categories initialized";
425         else
426             qDebug() << "Failed to initialize categories";
427 
428         initCatReply->deleteLater();
429         initCatReply = 0;
430     }
431     //! [Initialize categories reply]
432 
categories()433     void categories() {
434         QPlaceCategory pizza;
435         //! [Top level categories]
436         QList<QPlaceCategory> topLevelCategories = manager->childCategories();
437         foreach (const QPlaceCategory &category, topLevelCategories)
438             qDebug() << category.name();
439         //! [Top level categories]
440 
441         //! [Child categories]
442         QList<QPlaceCategory> childCategories = manager->childCategories(pizza.categoryId());
443         //! [Child categories]
444     }
445 
446     //! [Save category handler]
handleSaveCategoryReply()447     void handleSaveCategoryReply() {
448         if (saveCategoryReply->error() == QPlaceReply::NoError) {
449             qDebug() << "Saved category id =" << saveCategoryReply->id();
450         }
451 
452         saveCategoryReply->deleteLater();
453         saveCategoryReply = 0;
454     }
455     //! [Save category handler]
456 
457     //! [Remove category handler]
handleRemoveCategoryReply()458     void handleRemoveCategoryReply() {
459         if (removeCategoryReply->error() == QPlaceReply::NoError)
460             qDebug() << "Removal of category identified by"
461                      << removeCategoryReply->id() << "was successful";
462 
463         removeCategoryReply->deleteLater(); //discard reply
464         removeCategoryReply = 0;
465     }
466     //! [Remove category handler]
467 
468     //! [Content handler]
contentHandler()469     void contentHandler() {
470         if (contentReply->error() == QPlaceReply::NoError)  {
471             place.insertContent(contentReply->request().contentType(),
472                                 contentReply->content());
473         }
474     }
475     //! [Content handler]
476 
phoneNumbers()477     void phoneNumbers() {
478         //! [Phone numbers]
479         if (place.contactTypes().contains(QPlaceContactDetail::Phone)) {
480             foreach (const QPlaceContactDetail &number, place.contactDetails(QPlaceContactDetail::Phone))
481                 qDebug() << number.label() << ":" << number.value();
482         }
483         //! [Phone numbers]
484     }
485 
486 
openingHours()487     void openingHours() {
488         //! [Opening hours]
489         if (place.extendedAttributeTypes().contains(QPlaceAttribute::OpeningHours))
490             qDebug() << place.extendedAttribute(QPlaceAttribute::OpeningHours).text();
491         //! [Opening hours]
492     }
493 
494     //! [Match places handler]
matchHandler()495     void matchHandler() {
496         if (matchReply->error() == QPlaceReply::NoError) {
497             foreach (const QPlace place, matchReply->places()) {
498                 if (place != QPlace())
499                     qDebug() << "Place is a favorite with name" << place.name();
500                 else
501                     qDebug() << "Place is not a favorite";
502             }
503         }
504 
505         matchReply->deleteLater();
506         matchReply = 0;
507     }
508     //! [Match places handler]
509 
convertSearchResult()510     void convertSearchResult() {
511         QPlaceSearchResult result;
512         //! [Convert search result]
513         if (result.type() == QPlaceSearchResult::PlaceResult) {
514             QPlaceResult placeResult = result;
515             qDebug() << placeResult.place().name();
516             qDebug() << placeResult.place().location().coordinate();
517             qDebug() << placeResult.distance();
518         }
519         //! [Convert search result]
520     }
521 
522 QPlaceSearchReply *searchReply;
523 QPlaceManager *manager;
524 QPlaceDetailsReply *detailsReply;
525 QPlaceContentReply *contentReply;
526 QPlaceSearchSuggestionReply *suggestionReply;
527 QPlaceIdReply *savePlaceReply;
528 QPlaceIdReply *removePlaceReply;
529 QPlaceIdReply *saveCategoryReply;
530 QPlaceIdReply *removeCategoryReply;
531 QPlaceReply *initCatReply;
532 QPlaceMatchReply *matchReply;
533 QPlace place;
534 };
535 
536 class ManagerEngine : public QObject
537 {
538 };
539 
540 //! [Implement reply pt1]
541 class SearchReply : public QPlaceSearchReply
542 {
543 public:
SearchReply(ManagerEngine * engine)544     explicit SearchReply(ManagerEngine *engine)
545         : QPlaceSearchReply(engine), m_engine(engine){}
546 
547     ~SearchReply();
548     void setResults(const QList<QPlaceSearchResult> &results);
549     void setRequest(const QPlaceSearchRequest &request);
550 //! [Implement reply pt1]
551 
552 //! [Implement reply pt2]
553     void triggerDone(QPlaceReply::Error error = QPlaceReply::NoError,
554                      const QString &errorString = QString());
555 
556     ManagerEngine *m_engine;
557 };
558 //! [Implement reply pt2]
559 
560 class SearchSuggestionReply : public QPlaceSearchSuggestionReply
561 {
562 public:
563     void triggerDone(QPlaceReply::Error error = QPlaceReply::NoError,
564                      const QString &errorString = QString());
565 
566     ManagerEngine *m_engine;
567 
568 };
569 
570 //! [Trigger done]
triggerDone(QPlaceReply::Error error,const QString & errorString)571 void SearchSuggestionReply::triggerDone(QPlaceReply::Error error,
572                          const QString &errorString)
573 {
574     if (error != QPlaceReply::NoError) {
575         this->setError(error,errorString);
576         QMetaObject::invokeMethod(m_engine, "error", Qt::QueuedConnection,
577                                   Q_ARG(QPlaceReply *,this),
578                                   Q_ARG(QPlaceReply::Error, error),
579                                   Q_ARG(QString, errorString));
580         QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
581                                   Q_ARG(QPlaceReply::Error, error),
582                                   Q_ARG(QString, errorString));
583     }
584 
585     this->setFinished(true);
586     QMetaObject::invokeMethod(m_engine, "finished", Qt::QueuedConnection,
587                               Q_ARG(QPlaceReply *,this));
588     QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
589 }
590 //! [Trigger done]
591