1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtSystems module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL21$ |
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 2.1 or version 3 as published by the Free |
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
22 | ** following information to ensure the GNU Lesser General Public License |
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
25 | ** |
26 | ** As a special exception, The Qt Company gives you certain additional |
27 | ** rights. These rights are described in The Qt Company LGPL Exception |
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
29 | ** |
30 | ** $QT_END_LICENSE$ |
31 | ** |
32 | ****************************************************************************/ |
33 | |
34 | #include "qdeclarativeserviceold_p.h" |
35 | |
36 | #include <QQmlEngine> |
37 | #include <QQmlInfo> |
38 | |
39 | QT_BEGIN_NAMESPACE |
40 | |
41 | /*! |
42 | \qmltype Service |
43 | \instantiates QDeclarativeService |
44 | |
45 | \brief The Service element holds an instance of a service object. |
46 | \inherits QObject |
47 | |
48 | \ingroup qml-serviceframework |
49 | |
50 | The Service element is part of the Qt ServiceFramework API and |
51 | provides a client instance of the service object. This element is a simplified |
52 | reflection of the QServiceInterfaceDescriptor class that allows the specification of |
53 | the Service::interfaceName to locate the default service implemented at this interface. |
54 | |
55 | \sa ServiceList |
56 | */ |
57 | QDeclarativeService::QDeclarativeService() |
58 | : m_serviceInstance(0), m_componentComplete(false) |
59 | { |
60 | m_serviceManager = new QServiceManager(); |
61 | } |
62 | |
63 | QDeclarativeService::~QDeclarativeService() |
64 | { |
65 | delete m_serviceInstance; |
66 | } |
67 | |
68 | /*! |
69 | \qmlproperty bool Service::valid read-only |
70 | |
71 | This property holds whether a default service was found at the |
72 | interface name and corresponds to QServiceInterfaceDescriptor::isValid(). |
73 | */ |
74 | bool QDeclarativeService::isValid() const |
75 | { |
76 | return m_descriptor.isValid(); |
77 | } |
78 | |
79 | void QDeclarativeService::setInterfaceDesc(const QServiceInterfaceDescriptor &desc) |
80 | { |
81 | if (desc == m_descriptor) |
82 | return; |
83 | |
84 | m_descriptor = desc; |
85 | |
86 | if (m_serviceInstance) |
87 | delete m_serviceInstance; |
88 | setServiceObject(0); |
89 | } |
90 | |
91 | QServiceInterfaceDescriptor QDeclarativeService::interfaceDesc() const |
92 | { |
93 | return m_descriptor; |
94 | } |
95 | |
96 | /*! |
97 | \qmlproperty QString Service::interfaceName |
98 | |
99 | This property holds the interface name of the service that |
100 | corresponds to QServiceInterfaceDescriptor::interfaceName(). |
101 | */ |
102 | void QDeclarativeService::setInterfaceName(const QString &serviceInterface) |
103 | { |
104 | m_interface = serviceInterface; |
105 | updateDescriptor(); |
106 | } |
107 | |
108 | QString QDeclarativeService::interfaceName() const |
109 | { |
110 | if (isValid()) |
111 | return m_descriptor.interfaceName(); |
112 | else |
113 | return "No Interface" ; |
114 | } |
115 | |
116 | /*! |
117 | \qmlproperty QString Service::serviceName |
118 | |
119 | This property holds the service name of the service that |
120 | corresponds to QServiceInterfaceDescriptor::serviceName(). |
121 | */ |
122 | QString QDeclarativeService::serviceName() const |
123 | { |
124 | if (isValid()) |
125 | return m_descriptor.serviceName(); |
126 | else |
127 | return "No Service" ; |
128 | } |
129 | |
130 | void QDeclarativeService::setServiceName(const QString &service) |
131 | { |
132 | m_service = service; |
133 | } |
134 | |
135 | /*! |
136 | \qmlproperty int Service::majorVersion |
137 | |
138 | This property holds the major version number of the service that |
139 | corresponds to QServiceInterfaceDescriptor::majorVersion(). |
140 | */ |
141 | int QDeclarativeService::majorVersion() const |
142 | { |
143 | if (isValid()) |
144 | return m_descriptor.majorVersion(); |
145 | else |
146 | return 0; |
147 | } |
148 | |
149 | void QDeclarativeService::setMajorVersion(int version) |
150 | { |
151 | m_major = version; |
152 | updateDescriptor(); |
153 | } |
154 | |
155 | /*! |
156 | \qmlproperty int Service::minorVersion |
157 | |
158 | This property holds the minor version number of the service that |
159 | corresponds to QServiceInterfaceDescriptor::minorVersion(). |
160 | */ |
161 | int QDeclarativeService::minorVersion() const |
162 | { |
163 | if (isValid()) |
164 | return m_descriptor.minorVersion(); |
165 | else |
166 | return 0; |
167 | } |
168 | |
169 | void QDeclarativeService::setMinorVersion(int version) |
170 | { |
171 | m_minor = version; |
172 | updateDescriptor(); |
173 | } |
174 | |
175 | /*! |
176 | \qmlproperty QObject* Service::serviceObject |
177 | |
178 | This property holds an instance of the service object which |
179 | can be used to make metaobject calls to the service. This |
180 | corresponds to QServiceManager::loadInterface(). |
181 | */ |
182 | QObject* QDeclarativeService::serviceObject() |
183 | { |
184 | if (m_serviceInstance) { |
185 | return m_serviceInstance; |
186 | } |
187 | |
188 | if (isValid()) { |
189 | QObject *object = m_serviceManager->loadInterface(descriptor: m_descriptor); |
190 | setServiceObject(object); |
191 | if (!m_serviceInstance) { |
192 | emit error(errorString: QLatin1String("Failed to create object" )); |
193 | return m_serviceInstance; |
194 | } |
195 | emit serviceObjectChanged(); |
196 | connect(sender: m_serviceInstance, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)), |
197 | receiver: this, SLOT(IPCFault(QService::UnrecoverableIPCError))); |
198 | m_error.clear(); |
199 | return m_serviceInstance; |
200 | } else { |
201 | return 0; |
202 | } |
203 | } |
204 | |
205 | /*! |
206 | \qmlproperty QString Service::error |
207 | |
208 | This property holds the last error the was received, if any |
209 | |
210 | */ |
211 | |
212 | QString QDeclarativeService::lastError() const |
213 | { |
214 | return m_error; |
215 | } |
216 | |
217 | void QDeclarativeService::IPCFault(QService::UnrecoverableIPCError errorValue) |
218 | { |
219 | switch (errorValue) { |
220 | default: |
221 | case QService::ErrorUnknown: |
222 | m_error = QLatin1String("IPC Error: Unkown Error" ); |
223 | break; |
224 | case QService::ErrorServiceNoLongerAvailable: |
225 | m_error = QLatin1String("IPC Error: Service no longer available" ); |
226 | break; |
227 | case QService::ErrorOutofMemory: |
228 | m_error = QLatin1String("IPC Error: Out of memory" ); |
229 | break; |
230 | case QService::ErrorPermissionDenied: |
231 | m_error = QLatin1String("IPC Error: Permission Denied" ); |
232 | break; |
233 | case QService::ErrorInvalidArguments: |
234 | m_error = QLatin1String("IPC Error: Invalid Arguments" ); |
235 | break; |
236 | } |
237 | emit error(errorString: m_error); |
238 | m_serviceInstance->deleteLater(); |
239 | setServiceObject(0); |
240 | } |
241 | |
242 | void QDeclarativeService::updateDescriptor() |
243 | { |
244 | if (!m_componentComplete) |
245 | return; |
246 | |
247 | if (m_interface.isEmpty()) |
248 | return; |
249 | |
250 | QServiceInterfaceDescriptor new_desc; |
251 | |
252 | if (m_minor == 0 && m_major == 0 && m_service.isEmpty()){ |
253 | new_desc = m_serviceManager->interfaceDefault(interfaceName: m_interface); |
254 | } |
255 | else { |
256 | QServiceFilter filter; |
257 | if (!m_service.isEmpty()) |
258 | filter.setServiceName(m_service); |
259 | |
260 | |
261 | if (m_minor != 0 || m_major != 0) { |
262 | const QString version = QString::number(m_major) + "." + QString::number(m_minor); |
263 | filter.setInterface(interfaceName: m_interface, version); |
264 | } |
265 | |
266 | QList<QServiceInterfaceDescriptor> list = m_serviceManager->findInterfaces(filter); |
267 | if (!list.isEmpty()) |
268 | new_desc = list.takeFirst(); |
269 | } |
270 | |
271 | if (new_desc != m_descriptor) { |
272 | m_descriptor = new_desc; |
273 | if (m_serviceInstance) |
274 | emit serviceObjectChanged(); |
275 | } |
276 | |
277 | if (!isValid()) { |
278 | qWarning() << "WARNING: No service found for interface name: " << m_interface << m_service << m_major << m_minor; |
279 | } |
280 | } |
281 | |
282 | void QDeclarativeService::setServiceObject(QObject *object) |
283 | { |
284 | if (m_serviceInstance != object) { |
285 | m_serviceInstance = object; |
286 | emit serviceObjectChanged(); |
287 | } |
288 | } |
289 | |
290 | void QDeclarativeService::classBegin() |
291 | { |
292 | |
293 | } |
294 | |
295 | void QDeclarativeService::componentComplete() |
296 | { |
297 | m_componentComplete = true; |
298 | updateDescriptor(); |
299 | } |
300 | |
301 | bool QDeclarativeService::operator ==(const QServiceInterfaceDescriptor& other ) const |
302 | { |
303 | if ( m_descriptor == other) |
304 | return true; |
305 | |
306 | return false; |
307 | } |
308 | |
309 | /*! |
310 | \qmltype ServiceList |
311 | \instantiates QDeclarativeServiceList |
312 | |
313 | \brief The ServiceList element holds a list of \l Service elements. |
314 | \inherits QObject |
315 | |
316 | \ingroup qml-serviceframework |
317 | |
318 | The ServiceList element is part of the Qt ServiceFramework API and |
319 | provides a list of \l Service elements at the interface ServiceList::interfaceName with |
320 | minimum version match ServiceList::minVersion properties. This list can be used to |
321 | select the desired service and instantiate a service object for access via the QMetaObject. |
322 | |
323 | This element is a simplified reflection of the QServiceFilter class that provides a list |
324 | of simplified QServiceInterfaceDescriptors. Similarly, if the ServiceList::serviceName |
325 | and ServiceList::versionMatch are not provided they will respectively default to an empty |
326 | string with a minimum verison match. |
327 | |
328 | \sa Service |
329 | */ |
330 | QDeclarativeServiceList::QDeclarativeServiceList() |
331 | : m_service(QString()), |
332 | m_interface(), |
333 | m_major(1), |
334 | m_minor(1), |
335 | m_match(QDeclarativeServiceList::Minimum), |
336 | m_componentComplete(false) |
337 | { |
338 | serviceManager = new QServiceManager(this); |
339 | } |
340 | |
341 | QDeclarativeServiceList::~QDeclarativeServiceList() |
342 | { |
343 | while (m_services.count()) |
344 | delete m_services.takeFirst(); |
345 | } |
346 | /*! |
347 | \qmlproperty QString ServiceList::serviceName |
348 | |
349 | This property holds the interface name of the services that |
350 | corresponds to setting QServiceFilter::setService(). |
351 | */ |
352 | void QDeclarativeServiceList::setServiceName(const QString &service) |
353 | { |
354 | m_service = service; |
355 | updateFilterResults(); |
356 | if (m_componentComplete) |
357 | emit serviceNameChanged(); |
358 | } |
359 | |
360 | QString QDeclarativeServiceList::serviceName() const |
361 | { |
362 | return m_service; |
363 | } |
364 | |
365 | /*! |
366 | \qmlproperty QString ServiceList::interfaceName |
367 | |
368 | This property holds the interface name of the services that |
369 | corresponds to setting QServiceFilter::setInterface(). |
370 | */ |
371 | void QDeclarativeServiceList::setInterfaceName(const QString &serviceInterface) |
372 | { |
373 | m_interface = serviceInterface; |
374 | updateFilterResults(); |
375 | if (m_componentComplete) |
376 | emit interfaceNameChanged(); |
377 | } |
378 | |
379 | QString QDeclarativeServiceList::interfaceName() const |
380 | { |
381 | return m_interface; |
382 | } |
383 | |
384 | /*! |
385 | \qmlproperty int ServiceList::majorVersion |
386 | |
387 | This property holds the major version number of the service filter that |
388 | corresponds to QServiceFilter::majorVersion(). |
389 | */ |
390 | void QDeclarativeServiceList::setMajorVersion(int major) |
391 | { |
392 | m_major = major; |
393 | updateFilterResults(); |
394 | if (m_componentComplete) |
395 | emit majorVersionChanged(); |
396 | } |
397 | |
398 | int QDeclarativeServiceList::majorVersion() const |
399 | { |
400 | return m_major; |
401 | } |
402 | |
403 | /*! |
404 | \qmlproperty int ServiceList::minorVersion |
405 | |
406 | This property holds the minor version number of the service filter that |
407 | corresponds to QServiceFilter::minorVersion(). |
408 | */ |
409 | void QDeclarativeServiceList::setMinorVersion(int minor) |
410 | { |
411 | m_minor = minor; |
412 | updateFilterResults(); |
413 | if (m_componentComplete) |
414 | emit minorVersionChanged(); |
415 | } |
416 | |
417 | int QDeclarativeServiceList::minorVersion() const |
418 | { |
419 | return m_minor; |
420 | } |
421 | |
422 | /*! |
423 | \qmlproperty int ServiceList::monitorServiceRegistrations |
424 | |
425 | This property controls the behaviour of the list when new services are |
426 | registered or deregistered. Setting this property to true means the list |
427 | will be automatically updated when a service is added or removed. Caution, |
428 | your service object will be deleted if the service is unregistered, even if |
429 | the service is still running. |
430 | */ |
431 | |
432 | void QDeclarativeServiceList::setMonitorServiceRegistrations(bool updates) |
433 | { |
434 | if (updates == false) { |
435 | disconnect(receiver: this, SLOT(servicesAddedRemoved())); |
436 | } |
437 | else { |
438 | connect(sender: serviceManager, SIGNAL(serviceAdded(QString,QService::Scope)), |
439 | receiver: this, SLOT(servicesAddedRemoved())); |
440 | connect(sender: serviceManager, SIGNAL(serviceRemoved(QString,QService::Scope)), |
441 | receiver: this, SLOT(servicesAddedRemoved())); |
442 | } |
443 | |
444 | if (m_dynamicUpdates != updates) |
445 | emit monitorServiceRegistrationsChanged(); |
446 | |
447 | m_dynamicUpdates = updates; |
448 | } |
449 | |
450 | void QDeclarativeServiceList::servicesAddedRemoved() |
451 | { |
452 | // invoke in another event loop run |
453 | QMetaObject::invokeMethod(obj: this, member: "updateServiceList" , type: Qt::QueuedConnection); |
454 | } |
455 | |
456 | bool QDeclarativeServiceList::monitorServiceRegistrations() const |
457 | { |
458 | return m_dynamicUpdates; |
459 | } |
460 | |
461 | /*! |
462 | \qmlproperty enumeration ServiceList::versionMatch |
463 | |
464 | This property holds the version match rule of the service filter that |
465 | corresponds to QServiceFilter::versionMatchRule(). Within QML the values |
466 | ServiceList.Exact and ServiceList.Minimum correspond to |
467 | QServiceFilter::ExactVersionMatch and QServiceFilter::MinimumVersionMatch |
468 | respectively. |
469 | */ |
470 | void QDeclarativeServiceList::setVersionMatch(MatchRule match) |
471 | { |
472 | m_match = match; |
473 | updateFilterResults(); |
474 | if (m_componentComplete) |
475 | emit versionMatchChanged(); |
476 | } |
477 | |
478 | QDeclarativeServiceList::MatchRule QDeclarativeServiceList::versionMatch() const |
479 | { |
480 | return m_match; |
481 | } |
482 | |
483 | |
484 | void QDeclarativeServiceList::updateServiceList() |
485 | { |
486 | if (!m_componentComplete) |
487 | return; |
488 | |
489 | const QString version = QString::number(m_major) + "." + QString::number(m_minor); |
490 | |
491 | QServiceFilter filter; |
492 | |
493 | if (!m_service.isEmpty()) |
494 | filter.setServiceName(m_service); |
495 | |
496 | if (m_match == QDeclarativeServiceList::Exact) |
497 | filter.setInterface(interfaceName: m_interface, version, rule: QServiceFilter::ExactVersionMatch); |
498 | else if (!m_interface.isEmpty()) |
499 | filter.setInterface(interfaceName: m_interface, version); |
500 | |
501 | const QList<QServiceInterfaceDescriptor> newlist = serviceManager->findInterfaces(filter); |
502 | |
503 | QSet<QServiceInterfaceDescriptor> currentServices = QSet<QServiceInterfaceDescriptor>::fromList(list: m_currentList); |
504 | QSet<QServiceInterfaceDescriptor> newServices = QSet<QServiceInterfaceDescriptor>::fromList(list: newlist); |
505 | |
506 | if (currentServices == newServices) { |
507 | return; |
508 | } |
509 | |
510 | const QSet<QServiceInterfaceDescriptor> addServices = newServices.subtract(other: currentServices); |
511 | const QSet<QServiceInterfaceDescriptor> delServices = currentServices.subtract( |
512 | other: QSet<QServiceInterfaceDescriptor>::fromList(list: newlist)); |
513 | |
514 | foreach (const QServiceInterfaceDescriptor &desc, delServices) { |
515 | foreach (QDeclarativeService *service, m_services) { |
516 | if (*service == desc) { |
517 | m_services.removeOne(t: service); |
518 | delete service; |
519 | } |
520 | } |
521 | m_currentList.removeOne(t: desc); |
522 | } |
523 | |
524 | foreach (const QServiceInterfaceDescriptor &desc, addServices) { |
525 | QDeclarativeService *service = new QDeclarativeService(); |
526 | service->setInterfaceDesc(desc); |
527 | m_services.append(t: service); |
528 | m_currentList.append(t: desc); |
529 | } |
530 | |
531 | emit resultsChanged(); |
532 | } |
533 | |
534 | void QDeclarativeServiceList::updateFilterResults() |
535 | { |
536 | if (!m_componentComplete) |
537 | return; |
538 | |
539 | const QString version = QString::number(m_major) + "." + QString::number(m_minor); |
540 | |
541 | QServiceFilter filter; |
542 | |
543 | if (!m_service.isEmpty()) |
544 | filter.setServiceName(m_service); |
545 | |
546 | if (m_match == QDeclarativeServiceList::Exact) |
547 | filter.setInterface(interfaceName: m_interface, version, rule: QServiceFilter::ExactVersionMatch); |
548 | else if (!m_interface.isEmpty()) |
549 | filter.setInterface(interfaceName: m_interface, version); |
550 | |
551 | QList<QServiceInterfaceDescriptor> list = serviceManager->findInterfaces(filter); |
552 | |
553 | if (list == m_currentList) { |
554 | return; |
555 | } |
556 | |
557 | m_currentList = list; |
558 | |
559 | while (m_services.count()) //for now we refresh the entire list |
560 | delete m_services.takeFirst(); |
561 | |
562 | for (int i = 0; i < list.size(); i++) { |
563 | QDeclarativeService *service = new QDeclarativeService(); |
564 | service->setInterfaceDesc(list.at(i)); |
565 | m_services.append(t: service); |
566 | } |
567 | |
568 | emit resultsChanged(); |
569 | } |
570 | |
571 | /*! |
572 | \qmlproperty QQmlListProperty ServiceList::services |
573 | |
574 | This property holds the list of \l Service elements that match |
575 | the Service::interfaceName and minimum Service::versionNumber properties. |
576 | */ |
577 | QQmlListProperty<QDeclarativeService> QDeclarativeServiceList::services() |
578 | { |
579 | return QQmlListProperty<QDeclarativeService>(this, |
580 | 0, |
581 | s_append, |
582 | s_count, |
583 | s_at, |
584 | s_clear); |
585 | } |
586 | |
587 | void QDeclarativeServiceList::classBegin() |
588 | { |
589 | } |
590 | |
591 | void QDeclarativeServiceList::componentComplete() |
592 | { |
593 | if (!m_componentComplete) { |
594 | m_componentComplete = true; |
595 | updateFilterResults(); |
596 | } |
597 | } |
598 | |
599 | void QDeclarativeServiceList::listUpdated() |
600 | { |
601 | if (m_componentComplete) |
602 | emit resultsChanged(); |
603 | } |
604 | |
605 | void QDeclarativeServiceList::s_append(QQmlListProperty<QDeclarativeService> *prop, QDeclarativeService *service) |
606 | { |
607 | QDeclarativeServiceList* list = static_cast<QDeclarativeServiceList*>(prop->object); |
608 | list->m_services.append(t: service); |
609 | list->listUpdated(); |
610 | } |
611 | int QDeclarativeServiceList::s_count(QQmlListProperty<QDeclarativeService> *prop) |
612 | { |
613 | return static_cast<QDeclarativeServiceList*>(prop->object)->m_services.count(); |
614 | } |
615 | |
616 | QDeclarativeService* QDeclarativeServiceList::s_at(QQmlListProperty<QDeclarativeService> *prop, int index) |
617 | { |
618 | return static_cast<QDeclarativeServiceList*>(prop->object)->m_services[index]; |
619 | } |
620 | |
621 | void QDeclarativeServiceList::s_clear(QQmlListProperty<QDeclarativeService> *prop) |
622 | { |
623 | QDeclarativeServiceList* list = static_cast<QDeclarativeServiceList*>(prop->object); |
624 | qDeleteAll(c: list->m_services); |
625 | list->m_services.clear(); |
626 | list->listUpdated(); |
627 | } |
628 | #include "moc_qdeclarativeserviceold_p.cpp" |
629 | |
630 | QT_END_NAMESPACE |
631 | |