1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtLocation module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
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 http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qdeclarativecategory_p.h"
38#include "qdeclarativeplaceicon_p.h"
39#include "qdeclarativegeoserviceprovider_p.h"
40#include "error_messages_p.h"
41
42#include <QtQml/QQmlInfo>
43#include <QtLocation/QGeoServiceProvider>
44#include <QtLocation/QPlaceManager>
45#include <QCoreApplication>
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \qmltype Category
51 \instantiates QDeclarativeCategory
52 \inqmlmodule QtLocation
53 \ingroup qml-QtLocation5-places
54 \ingroup qml-QtLocation5-places-data
55
56 \since QtLocation 5.5
57
58 \brief The Category type represents a category that a \l Place can be associated with.
59
60 Categories are used to search for places based on the categories they are associated with. The
61 list of available categories can be obtained from the \l CategoryModel. The
62 \l PlaceSearchModel has a \l {PlaceSearchModel::categories}{categories} property that is used
63 to limit the search results to places with the specified categories.
64
65 If the \l Plugin supports it, categories can be created or removed. To create a new category
66 construct a new Category object and set its properties, then invoke the \l save() method.
67
68 \snippet declarative/maps.qml QtLocation import
69 \codeline
70 \snippet declarative/places.qml Category
71 \dots 0
72 \snippet declarative/places.qml Category save
73
74 To remove a category ensure that the \l plugin and categoryId properties are set and call the
75 \l remove() method.
76
77 \sa CategoryModel
78*/
79
80QDeclarativeCategory::QDeclarativeCategory(QObject *parent)
81: QObject(parent), m_icon(0), m_plugin(0), m_reply(0), m_complete(false), m_status(Ready)
82{
83}
84
85QDeclarativeCategory::QDeclarativeCategory(const QPlaceCategory &category,
86 QDeclarativeGeoServiceProvider *plugin,
87 QObject *parent)
88: QObject(parent), m_category(category), m_icon(0), m_plugin(plugin), m_reply(0),
89 m_complete(false), m_status(Ready)
90{
91 setCategory(category);
92}
93
94QDeclarativeCategory::~QDeclarativeCategory() {}
95
96// From QQmlParserStatus
97void QDeclarativeCategory::componentComplete()
98{
99 // delayed instantiation of QObject based properties.
100 if (!m_icon) {
101 m_icon = new QDeclarativePlaceIcon(this);
102 m_icon->setPlugin(m_plugin);
103 }
104
105 m_complete = true;
106}
107
108/*!
109 \qmlproperty Plugin Category::plugin
110
111 This property holds the location based service to which the category belongs.
112*/
113void QDeclarativeCategory::setPlugin(QDeclarativeGeoServiceProvider *plugin)
114{
115 if (m_plugin == plugin)
116 return;
117
118 m_plugin = plugin;
119 if (m_complete)
120 emit pluginChanged();
121
122 if (m_icon && m_icon->parent() == this && !m_icon->plugin())
123 m_icon->setPlugin(m_plugin);
124
125 if (!m_plugin)
126 return;
127
128 if (m_plugin->isAttached()) {
129 pluginReady();
130 } else {
131 connect(sender: m_plugin, SIGNAL(attached()),
132 receiver: this, SLOT(pluginReady()));
133 }
134}
135
136QDeclarativeGeoServiceProvider *QDeclarativeCategory::plugin() const
137{
138 return m_plugin;
139}
140
141/*!
142 \internal
143*/
144void QDeclarativeCategory::pluginReady()
145{
146 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
147 QPlaceManager *placeManager = serviceProvider->placeManager();
148 if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) {
149 setStatus(status: Error, errorString: QCoreApplication::translate(context: CONTEXT_NAME, key: PLUGIN_ERROR)
150 .arg(a: m_plugin->name()).arg(a: serviceProvider->errorString()));
151 return;
152 }
153}
154
155
156/*!
157 \qmlproperty QPlaceCategory Category::category
158 \keyword Category::category
159
160 For details on how to use this property to interface between C++ and QML see
161 "\l {Category - QPlaceCategory} {Interfaces between C++ and QML Code}".
162*/
163void QDeclarativeCategory::setCategory(const QPlaceCategory &category)
164{
165 QPlaceCategory previous = m_category;
166 m_category = category;
167
168 if (category.name() != previous.name())
169 emit nameChanged();
170
171 if (category.categoryId() != previous.categoryId())
172 emit categoryIdChanged();
173
174 if (m_icon && m_icon->parent() == this) {
175 m_icon->setPlugin(m_plugin);
176 m_icon->setIcon(m_category.icon());
177 } else if (!m_icon || m_icon->parent() != this) {
178 m_icon = new QDeclarativePlaceIcon(m_category.icon(), m_plugin, this);
179 emit iconChanged();
180 }
181}
182
183QPlaceCategory QDeclarativeCategory::category()
184{
185 m_category.setIcon(m_icon ? m_icon->icon() : QPlaceIcon());
186 return m_category;
187}
188
189/*!
190 \qmlproperty string Category::categoryId
191
192 This property holds the identifier of the category. The categoryId is a string which uniquely
193 identifies this category within the categories \l plugin.
194*/
195void QDeclarativeCategory::setCategoryId(const QString &id)
196{
197 if (m_category.categoryId() != id) {
198 m_category.setCategoryId(id);
199 emit categoryIdChanged();
200 }
201}
202
203QString QDeclarativeCategory::categoryId() const
204{
205 return m_category.categoryId();
206}
207
208/*!
209 \qmlproperty string Category::name
210
211 This property holds string based name of the category.
212*/
213void QDeclarativeCategory::setName(const QString &name)
214{
215 if (m_category.name() != name) {
216 m_category.setName(name);
217 emit nameChanged();
218 }
219}
220
221QString QDeclarativeCategory::name() const
222{
223 return m_category.name();
224}
225
226/*!
227 \qmlproperty enumeration Category::visibility
228
229 This property holds the visibility of the category. It can be one of:
230
231 \table
232 \row
233 \li Category.UnspecifiedVisibility
234 \li The visibility of the category is unspecified. If saving a category, the
235 plugin will automatically set a default visibility to the category saved in the backend.
236 This default is dependent on the plugin implementation.
237 \row
238 \li Category.DeviceVisibility
239 \li The category is limited to the current device. The category will not be transferred
240 off of the device.
241 \row
242 \li Category.PrivateVisibility
243 \li The category is private to the current user. The category may be transferred to an
244 online service but is only ever visible to the current user.
245 \row
246 \li Category.PublicVisibility
247 \li The category is public.
248 \endtable
249
250 Note that visibility does not affect how \l{Place}s associated with
251 the category are displayed in the user-interface of an application
252 on the device. Instead, it defines the sharing semantics of the
253 category.
254*/
255QDeclarativeCategory::Visibility QDeclarativeCategory::visibility() const
256{
257 return static_cast<QDeclarativeCategory::Visibility>(m_category.visibility());
258}
259
260void QDeclarativeCategory::setVisibility(Visibility visibility)
261{
262 if (static_cast<QDeclarativeCategory::Visibility>(m_category.visibility()) == visibility)
263 return;
264
265 m_category.setVisibility(static_cast<QLocation::Visibility>(visibility));
266 emit visibilityChanged();
267}
268
269/*!
270 \qmlproperty PlaceIcon Category::icon
271
272 This property holds the image source associated with the category. To display the icon you can use
273 the \l Image type.
274*/
275QDeclarativePlaceIcon *QDeclarativeCategory::icon() const
276{
277 return m_icon;
278}
279
280void QDeclarativeCategory::setIcon(QDeclarativePlaceIcon *icon)
281{
282 if (m_icon == icon)
283 return;
284
285 if (m_icon && m_icon->parent() == this)
286 delete m_icon;
287
288 m_icon = icon;
289 emit iconChanged();
290}
291
292/*!
293 \qmlmethod string Category::errorString()
294
295 Returns a string description of the error of the last operation.
296 If the last operation completed successfully then the string is empty.
297*/
298QString QDeclarativeCategory::errorString() const
299{
300 return m_errorString;
301}
302
303void QDeclarativeCategory::setStatus(Status status, const QString &errorString)
304{
305 Status originalStatus = m_status;
306 m_status = status;
307 m_errorString = errorString;
308
309 if (originalStatus != m_status)
310 emit statusChanged();
311}
312
313/*!
314 \qmlproperty enumeration Category::status
315
316 This property holds the status of the category. It can be one of:
317
318 \table
319 \row
320 \li Category.Ready
321 \li No error occurred during the last operation, further operations may be performed on
322 the category.
323 \row
324 \li Category.Saving
325 \li The category is currently being saved, no other operations may be performed until the
326 current operation completes.
327 \row
328 \li Category.Removing
329 \li The category is currently being removed, no other operations can be performed until
330 the current operation completes.
331 \row
332 \li Category.Error
333 \li An error occurred during the last operation, further operations can still be
334 performed on the category.
335 \endtable
336*/
337QDeclarativeCategory::Status QDeclarativeCategory::status() const
338{
339 return m_status;
340}
341
342/*!
343 \qmlmethod void Category::save()
344
345 This method saves the category to the backend service.
346*/
347void QDeclarativeCategory::save(const QString &parentId)
348{
349 QPlaceManager *placeManager = manager();
350 if (!placeManager)
351 return;
352
353 m_reply = placeManager->saveCategory(category: category(), parentId);
354 connect(sender: m_reply, SIGNAL(finished()), receiver: this, SLOT(replyFinished()));
355 setStatus(status: QDeclarativeCategory::Saving);
356}
357
358/*!
359 \qmlmethod void Category::remove()
360
361 This method permanently removes the category from the backend service.
362*/
363void QDeclarativeCategory::remove()
364{
365 QPlaceManager *placeManager = manager();
366 if (!placeManager)
367 return;
368
369 m_reply = placeManager->removeCategory(categoryId: m_category.categoryId());
370 connect(sender: m_reply, SIGNAL(finished()), receiver: this, SLOT(replyFinished()));
371 setStatus(status: QDeclarativeCategory::Removing);
372}
373
374/*!
375 \internal
376*/
377void QDeclarativeCategory::replyFinished()
378{
379 if (!m_reply)
380 return;
381
382 if (m_reply->error() == QPlaceReply::NoError) {
383 switch (m_reply->type()) {
384 case (QPlaceReply::IdReply) : {
385 QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(object: m_reply);
386
387 switch (idReply->operationType()) {
388 case QPlaceIdReply::SaveCategory:
389 setCategoryId(idReply->id());
390 break;
391 case QPlaceIdReply::RemoveCategory:
392 setCategoryId(QString());
393 break;
394 default:
395 //Other operation types shouldn't ever be received.
396 break;
397 }
398 break;
399 }
400 default:
401 //other types of replies shouldn't ever be received.
402 break;
403 }
404
405 m_errorString.clear();
406
407 m_reply->deleteLater();
408 m_reply = 0;
409
410 setStatus(status: QDeclarativeCategory::Ready);
411 } else {
412 QString errorString = m_reply->errorString();
413
414 m_reply->deleteLater();
415 m_reply = 0;
416
417 setStatus(status: QDeclarativeCategory::Error, errorString);
418 }
419}
420
421/*!
422 \internal
423 Helper function to return the manager, this manager is intended to be used to perform the next
424 operation. Sets status to Error and an appropriate m_errorString if the manager cannot be
425 obtained.
426*/
427QPlaceManager *QDeclarativeCategory::manager()
428{
429 if (m_status != QDeclarativeCategory::Ready && m_status != QDeclarativeCategory::Error)
430 return 0;
431
432 if (m_reply) {
433 m_reply->abort();
434 m_reply->deleteLater();
435 m_reply = 0;
436 }
437
438 if (!m_plugin) {
439 setStatus(status: Error, errorString: QCoreApplication::translate(context: CONTEXT_NAME, key: PLUGIN_PROPERTY_NOT_SET));
440 return 0;
441 }
442
443 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
444 if (!serviceProvider) {
445 setStatus(status: Error, errorString: QCoreApplication::translate(context: CONTEXT_NAME, key: PLUGIN_NOT_VALID));
446 return 0;
447 }
448 QPlaceManager *placeManager = serviceProvider->placeManager();
449 if (!placeManager) {
450 setStatus(status: Error, errorString: QCoreApplication::translate(context: CONTEXT_NAME, key: PLUGIN_ERROR)
451 .arg(a: m_plugin->name()).arg(a: serviceProvider->errorString()));
452 return 0;
453 }
454
455 return placeManager;
456}
457
458QT_END_NAMESPACE
459

source code of qtlocation/src/location/declarativeplaces/qdeclarativecategory.cpp