|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation, version 2.1 of the License. |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU Lesser General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Lesser General Public License |
|
15 * along with this program. If not, |
|
16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". |
|
17 * |
|
18 * Description: |
|
19 * |
|
20 */ |
|
21 |
|
22 #include "xqservicelog.h" |
|
23 |
|
24 #include <xqserviceprovider.h> |
|
25 #include <qmetaobject.h> |
|
26 #include <QByteArray> |
|
27 |
|
28 #include <xqserviceadaptor.h> |
|
29 //#include <xqserviceservice.h> |
|
30 #include <xqserviceutil.h> |
|
31 |
|
32 /*! |
|
33 \class ServiceAdaptorProxy |
|
34 \brief Proxy class for converting signal and slot members into IPC message names |
|
35 */ |
|
36 class ServiceAdaptorProxy : public XQServiceAdaptor |
|
37 { |
|
38 Q_OBJECT |
|
39 |
|
40 public: |
|
41 ServiceAdaptorProxy(const QString &channel, QObject *parent=0); |
|
42 virtual ~ServiceAdaptorProxy() ; |
|
43 |
|
44 QString memberToMessage( const QByteArray& member ); |
|
45 }; |
|
46 |
|
47 ServiceAdaptorProxy::ServiceAdaptorProxy(const QString &channel, QObject *parent) : |
|
48 XQServiceAdaptor(channel, parent) |
|
49 { |
|
50 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::ServiceAdaptorProxy"); |
|
51 XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel)); |
|
52 } |
|
53 |
|
54 ServiceAdaptorProxy::~ServiceAdaptorProxy() |
|
55 { |
|
56 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::~ServiceAdaptorProxy"); |
|
57 } |
|
58 |
|
59 QString ServiceAdaptorProxy::memberToMessage( const QByteArray& member ) |
|
60 { |
|
61 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::memberToMessage"); |
|
62 XQSERVICE_DEBUG_PRINT("member: %s", member.constData()); |
|
63 // TO BE CHECKED |
|
64 // return m_channel + "::" + XQServiceAdaptor::memberToMessage( member ); |
|
65 return XQServiceAdaptor::memberToMessage( member ); |
|
66 } |
|
67 |
|
68 /*! |
|
69 \class XQServiceProvider_Private |
|
70 \inpublicgroup QtBaseModule |
|
71 |
|
72 \brief Private implementation of XQServiceProvider |
|
73 */ |
|
74 class XQServiceProvider_Private |
|
75 { |
|
76 public: |
|
77 XQServiceProvider_Private(const QString &service); |
|
78 |
|
79 ~XQServiceProvider_Private(); |
|
80 |
|
81 XQServiceAdaptor *m_adaptor; |
|
82 |
|
83 QString m_service; |
|
84 bool m_publishAllCalled; |
|
85 QObject* plugin; |
|
86 }; |
|
87 |
|
88 XQServiceProvider_Private::XQServiceProvider_Private(const QString &service) : |
|
89 m_adaptor(NULL), |
|
90 m_service(service), |
|
91 m_publishAllCalled(false), |
|
92 plugin(NULL) |
|
93 { |
|
94 XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::XQServiceProvider_Private"); |
|
95 XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service)); |
|
96 m_adaptor = new ServiceAdaptorProxy(service); |
|
97 } |
|
98 |
|
99 XQServiceProvider_Private::~XQServiceProvider_Private() |
|
100 { |
|
101 XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::~XQServiceProvider_Private"); |
|
102 delete m_adaptor; |
|
103 } |
|
104 |
|
105 /*! |
|
106 \class XQServiceProvider |
|
107 \inpublicgroup QtBaseModule |
|
108 |
|
109 \brief The XQServiceProvider class provides an interface to messages on a XQService service |
|
110 which simplifies remote slot invocations |
|
111 |
|
112 Service messages consist of a service name, a message name, and a list of parameter values. |
|
113 Qt extension dispatches service messages to the applications associated with the service |
|
114 name, on the application's \c{QPE/Application/appname} channel, where |
|
115 \c{appname} is the application's name. |
|
116 |
|
117 <b>Service registration</b> \n |
|
118 Service provider need to register it's service into the system before they can be used by |
|
119 the service client. Registration is done by creating a XML formatted service configuration |
|
120 file and defining the service in the provider's .pro-file. QMake will notice service provider |
|
121 from the .pro-file, with help of the service.prf file, and generate a make file that uses |
|
122 a helper application xqsreg.exe. The helper application sqsreg.exe will generate an application |
|
123 registration resource file ( _reg.rss) from the configuration-file and provider's definitions |
|
124 that include the needed declarations for the services provided. |
|
125 |
|
126 <b>Service Names Allocation</b> \n |
|
127 The harmonize service and interface names the Symba specific names and guidelines can be found |
|
128 from http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#Service. |
|
129 |
|
130 Before implementing a service you need to allocate the name according to the guidelines. Please |
|
131 inform intended service clients (customers) and matti.parnanen@nokia.com. |
|
132 |
|
133 <b>Service Configuration File</b> \n |
|
134 All the service configuration are added to the run-time service registry to make them available |
|
135 for service discovery and creating service requests. |
|
136 \note Only one service element with multiple interface is supported! |
|
137 |
|
138 To support services a new configuration was introduced to qmake and two new variables for |
|
139 that configuration: |
|
140 |
|
141 \code |
|
142 CONFIG = service |
|
143 service.file = <service configuration file path> |
|
144 service.options = <embeddable> (optional, default not embeddable), <hidden> (optional, default not hidden) |
|
145 \endcode |
|
146 |
|
147 The fornat of the service configuration file is same as XML format used in Qt Service Framework. |
|
148 Example configuration file: |
|
149 |
|
150 \code |
|
151 <?xml version="1.0" encoding="utf-8" ?> |
|
152 <service> |
|
153 <name>Music Fetcher</name> |
|
154 <filepath>No path</filepath> |
|
155 <description>Music Fetcher</description> |
|
156 <interface> |
|
157 <name><b>com.nokia.symbian.IMusicFetch</b></name> |
|
158 <version>1.0</version> |
|
159 <description>Interface for fetching music files</description> |
|
160 </interface> |
|
161 </service> |
|
162 \endcode |
|
163 |
|
164 \code |
|
165 <ELEMENT service ( name, filepath, description?, interface+ ) > |
|
166 <ELEMENT description ( #CDATA ) > |
|
167 <ELEMENT filepath ( #PCDATA ) > |
|
168 <ELEMENT interface ( '''name''', version, description?, capabilities?, customproperty* ) > |
|
169 <ELEMENT capabilities ( #PCDATA ) > |
|
170 <ELEMENT name ( #PCDATA ) > |
|
171 <ELEMENT version ( #PCDATA ) > |
|
172 <ELEMENT customproperty ( #CDATA ) > |
|
173 <ATTLIST customproperty key NMTOKEN #REQUIRED > |
|
174 \endcode |
|
175 |
|
176 Also the old format described below is supported, With old format you can not have custom properties, which |
|
177 for example are used for AIW purposes. |
|
178 \code |
|
179 <ELEMENT service ( description?, interface+ ) > |
|
180 <ATTLIST service name #CDATA #REQUIRED > |
|
181 <ATTLIST service filepath #CDATA #REQUIRED > |
|
182 <ELEMENT description ( #CDATA ) > |
|
183 <ELEMENT interface ( description? ) > |
|
184 <ATTLIST interface '''name''' #CDATA #REQUIRED > |
|
185 <ATTLIST interface version #CDATA #REQUIRED > |
|
186 <ATTLIST interface capabilities #CDATA #REQUIRED > |
|
187 \endcode |
|
188 |
|
189 <b>Changing service or interface names</b> \n |
|
190 Before you think about changing the name of the already released and used service implementation, read this |
|
191 http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#About_changing_service_or_interface_names |
|
192 first. |
|
193 |
|
194 The basic message is the service name, interface name and operation (message) slot signatures for the API. And for API changes you have to apply development time API deprecation process. |
|
195 |
|
196 <b>Service Registration tools</b> \n |
|
197 The needed utility files for service registration: |
|
198 - xqsreg.exe should be in \epoc32\tools or some other directory that can be found from the path |
|
199 - service.prf should be in \epoc32\tools\qt\mkspecs\features\symbian directory. |
|
200 |
|
201 If necessary you can copy those files to target directories from qthighway/bin. |
|
202 |
|
203 Sources for the xqsreg.exe can be found from the qthighway\xqsreg and it is also possible to compile it. |
|
204 - cd \qthighway\xqsreg |
|
205 - qmake -platform win32-mwc |
|
206 - make |
|
207 |
|
208 Usage: \n |
|
209 How to create a simple synchronously working service provider? |
|
210 \code |
|
211 class YourService : public XQServiceProvider |
|
212 { |
|
213 Q_OBJECT |
|
214 |
|
215 public: |
|
216 YourService ( ServiceApp *parent = 0 ); |
|
217 ~YourService (); |
|
218 |
|
219 public slots: |
|
220 void functionName1(); |
|
221 int functionName2(const QString& number, int times); |
|
222 |
|
223 private: |
|
224 ServiceApp *mServiceApp; |
|
225 }; |
|
226 \endcode |
|
227 |
|
228 Implementation: |
|
229 \code |
|
230 YourService::YourService(ServiceApp* parent) |
|
231 : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent) |
|
232 { |
|
233 publishAll(); |
|
234 } |
|
235 |
|
236 YourService::~YourService() { } |
|
237 |
|
238 void YourService::functionName1() { } |
|
239 |
|
240 int YourService::functionName2(const QString& number, int times) |
|
241 { |
|
242 int returnValue = 1; |
|
243 return returnValue; |
|
244 } |
|
245 \endcode |
|
246 |
|
247 Additions to .pro-file: |
|
248 \code |
|
249 CONFIG += service |
|
250 SERVICE.FILE = service_conf.xml |
|
251 SERVICE.OPTIONS = embeddable |
|
252 SERVICE.OPTIONS += hidden |
|
253 \endcode |
|
254 |
|
255 Service configuration file (service_conf.xml): |
|
256 \code |
|
257 <?xml version="1.0" encoding="utf-8" ?> |
|
258 <service> |
|
259 <name>yourservice</name> |
|
260 <filepath>No path</filepath> |
|
261 <description>Service description</description> |
|
262 <interface> |
|
263 <name>Interface</name> |
|
264 <version>1.0</version> |
|
265 <description>Interface description</description> |
|
266 </interface> |
|
267 </service> |
|
268 \endcode |
|
269 |
|
270 How to create a simple asynchronously working service provider? |
|
271 Header: |
|
272 \code |
|
273 class YourService : public XQServiceProvider |
|
274 { |
|
275 |
|
276 Q_OBJECT |
|
277 |
|
278 public: |
|
279 YourService ( ServiceApp *parent = 0 ); |
|
280 ~YourService (); |
|
281 void compleAsyncFunction(); |
|
282 |
|
283 public slots: |
|
284 void functionName1(); |
|
285 int functionName2(const QString& number, int times); |
|
286 |
|
287 private: |
|
288 ServiceApp *mServiceApp; |
|
289 int mAsyncRequestIndex; |
|
290 QVariant mReturnValue; |
|
291 |
|
292 }; |
|
293 \endcode |
|
294 |
|
295 Implementation: |
|
296 \code |
|
297 YourService::YourService(ServiceApp* parent) |
|
298 : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent) |
|
299 { |
|
300 publishAll(); |
|
301 } |
|
302 |
|
303 YourService::~YourService() { } |
|
304 |
|
305 void YourService::compleAsyncFunction() |
|
306 { |
|
307 completeRequest(mAsyncRequestIndex, mReturnValue); |
|
308 } |
|
309 |
|
310 void YourService::functionName1() |
|
311 { |
|
312 mAsyncRequestIndex = setCurrentRequestAsync(); |
|
313 mReturnValue.setValue(0); |
|
314 } |
|
315 |
|
316 int YourService::functionName2(const QString& number, int times) |
|
317 { |
|
318 mAsyncRequestIndex = setCurrentRequestAsync(); |
|
319 mReturnValue.setValue(1); |
|
320 return mReturnValue.toInt(); |
|
321 } |
|
322 \endcode |
|
323 |
|
324 <b>Examples:</b> \n |
|
325 The use of XQServiceProvider will be demonstrated using the \c{Time} |
|
326 service. This has a single message called \c{editTime()} which asks |
|
327 the service to pop up a dialog allowing the user to edit the current time. |
|
328 \code |
|
329 class TimeService : public XQServiceProvider |
|
330 { |
|
331 Q_OBJECT |
|
332 public: |
|
333 TimeService( QObject *parent = 0 ); |
|
334 |
|
335 public slots: |
|
336 void editTime(QTime time); |
|
337 }; |
|
338 |
|
339 TimeService::TimeService( QObject *parent ) |
|
340 : XQServiceProvider( "Time", parent ) |
|
341 { |
|
342 publishAll(); |
|
343 } |
|
344 \endcode |
|
345 |
|
346 The call to publishAll() causes all public slots within \c{TimeService} |
|
347 to be automatically registered as Service messages. This can be |
|
348 useful if the service has many message types. |
|
349 |
|
350 The client can send a request to the service using QtopiaServiceRequest: |
|
351 |
|
352 \code |
|
353 XQServiceRequest req( "Time", "editTime()" ); |
|
354 req << QTime::currentTime(); |
|
355 req.send(); |
|
356 \endcode |
|
357 |
|
358 <b>URI viewer</b> \n |
|
359 This is a simple example for implementing out-of-process scheme handlers. |
|
360 - "http", "https" and are handled via standard QDesktopServices::openUrl() function. |
|
361 This is fire-and-forget launch. The options are ignored and no control and signals available after the launch. |
|
362 - "appto" is routed to Activity Manager for opening the attached activity. |
|
363 This is fire-and-forget launch. The options are ignored and no control and signals available after the launch. |
|
364 - The "file" scheme is handled as the QFile based create below. |
|
365 So the com.nokia.symbian.IFileView interface is applied as for the QFile. |
|
366 |
|
367 Service application needs to publish support for: |
|
368 - The common interface "com.nokia.symbian.IUriView", and |
|
369 - The scheme(s), like "testo" in the example below. The custom custom property "schemes" contains one or more schemes as comma separated list (CSV) |
|
370 - The slot "view(QString)" to view the URI |
|
371 |
|
372 \code |
|
373 <?xml version="1.0" encoding="utf-8" ?> |
|
374 <service> |
|
375 <name>serviceapp</name> |
|
376 <filepath>No path</filepath> |
|
377 <description>Test service</description> |
|
378 <interface> |
|
379 <name>com.nokia.symbian.IUriView</name> |
|
380 <version>1.0</version> |
|
381 <description>Interface for showing URIs</description> |
|
382 <customproperty key="schemes">testto</customproperty> |
|
383 </interface> |
|
384 </service> |
|
385 \endcode |
|
386 |
|
387 An service application that offers support for a scheme implements the common "UriService" with the pre-defined "view" slot: |
|
388 |
|
389 \code |
|
390 class UriService : public XQServiceProvider |
|
391 { |
|
392 Q_OBJECT |
|
393 public: |
|
394 UriService( ServiceApp *parent = 0 ); |
|
395 ~UriService(); |
|
396 bool asyncAnswer() {return mAsyncAnswer;} |
|
397 void complete(bool ok); |
|
398 |
|
399 public slots: |
|
400 bool view(const QString& uri); |
|
401 |
|
402 private slots: |
|
403 void handleClientDisconnect(); |
|
404 |
|
405 private: |
|
406 ServiceApp* mServiceApp; |
|
407 bool mAsyncAnswer; |
|
408 int mAsyncReqId; |
|
409 bool mRetValue; |
|
410 }; |
|
411 \endcode |
|
412 |
|
413 Client application accesses the service via the URI: |
|
414 |
|
415 \code |
|
416 // Assume in example we have own scheme "testo" but this can be applied to |
|
417 // "mailto", etc. standard schemes. |
|
418 // |
|
419 // (As mentioned in the documentation, some schemes are CURRENTLY handled specially, |
|
420 // like "http" scheme uses QDesktopServices::openUrl). |
|
421 // |
|
422 QUrl url("testto://authority?param1=value1¶m1=value2"); |
|
423 |
|
424 // The difference to the previous example is is how request is created |
|
425 // via application mgr. |
|
426 |
|
427 request = mAiwMgr.create(url); |
|
428 if (request == NULL) |
|
429 { |
|
430 // No handlers for the URI |
|
431 return; |
|
432 } |
|
433 |
|
434 // Set function parameters |
|
435 QList<QVariant> args; |
|
436 args << uri.toSring(); |
|
437 request->setArguments(args); |
|
438 |
|
439 // Send the request |
|
440 bool res = request.send(); |
|
441 if (!res) |
|
442 { |
|
443 // Request failed. |
|
444 int error = request->lastError(); |
|
445 // Handle error |
|
446 } |
|
447 |
|
448 // If making multiple requests to same service, you can save the request as member variable |
|
449 // In this example all done. |
|
450 delete request; |
|
451 \endcode |
|
452 |
|
453 <b>File viewer</b> \n |
|
454 As for URis, a service application that support viewing a file with a dedicated MIME-type need to publish support for: |
|
455 - The common interface "com.nokia.symbian.IFileView". |
|
456 - The slot "view(QString)" to view the non-data-caged file by file name. |
|
457 - The slot "view(XQSharable)" to view the data-caged file by sharable file handle. |
|
458 - MIME type list (registered in the .pro file). |
|
459 So there are multiple service applications implementing the same interface. |
|
460 |
|
461 In service provider side you need the following entry in XML: |
|
462 |
|
463 \code |
|
464 <interface> |
|
465 <name>com.nokia.symbian.IFileView</name> |
|
466 <version>1.0</version> |
|
467 <description>Interface for showing Files</description> |
|
468 </interface> |
|
469 \endcode |
|
470 |
|
471 The file viewer application shall offer slots both for viewing filename (QString) and viewing sharable file (XQSharable): |
|
472 |
|
473 \code |
|
474 class FileService : public XQServiceProvider |
|
475 { |
|
476 Q_OBJECT |
|
477 public: |
|
478 FileService( ServiceApp *parent = 0 ); |
|
479 ~FileService(); |
|
480 bool asyncAnswer() {return mAsyncAnswer;} |
|
481 void complete(bool ok); |
|
482 |
|
483 public slots: |
|
484 bool view(QString file); |
|
485 bool view(XQSharableFile file); |
|
486 |
|
487 private slots: |
|
488 void handleClientDisconnect(); |
|
489 |
|
490 private: |
|
491 ServiceApp* mServiceApp; |
|
492 bool mAsyncAnswer; |
|
493 int mAsyncReqId; |
|
494 bool mRetValue; |
|
495 }; |
|
496 \endcode |
|
497 |
|
498 In the .pro file the service publishes the supported MIME types, e.g: |
|
499 |
|
500 \code |
|
501 RSS_RULES += \ |
|
502 "datatype_list = " \ |
|
503 " {" \ |
|
504 " DATATYPE" \ |
|
505 " {" \ |
|
506 " priority = EDataTypePriorityNormal;" \ |
|
507 " type = \"text/plain\";" \ |
|
508 " }" \ |
|
509 " };" \ |
|
510 \endcode |
|
511 |
|
512 In the client side (see the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release) access to |
|
513 file: |
|
514 |
|
515 \code |
|
516 // Not data caged file |
|
517 QFile file("C:\\data\\Others\\test.txt"); |
|
518 |
|
519 request = mAiwMgr.create(file); |
|
520 if (request == NULL) |
|
521 { |
|
522 // No handlers for the URI |
|
523 return; |
|
524 } |
|
525 // By default operation is "view(QString)" |
|
526 |
|
527 // Set function parameters |
|
528 QList<QVariant> args; |
|
529 args << file.fileName(); |
|
530 request->setArguments(args); |
|
531 |
|
532 // Send the request |
|
533 bool res = request.send(); |
|
534 if (!res) |
|
535 { |
|
536 // Request failed. |
|
537 int error = request->lastError(); |
|
538 |
|
539 // Handle error |
|
540 } |
|
541 |
|
542 // If making multiple requests to same service, you can save the request as member variable |
|
543 // In this example all done. |
|
544 delete request; |
|
545 \endcode |
|
546 |
|
547 <b>Sharable file viewer</b> \n |
|
548 The same rules as for file name based view applies, but different argument type (XQSharableFile) used |
|
549 in request. See the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release. |
|
550 |
|
551 \code |
|
552 XQSharableFile sf; |
|
553 // Open the file for sharing from own private directory |
|
554 // If you have handle available, just set it by "setHandle()" function |
|
555 if (!sf.open("c:\\private\\e0022e74\\test.txt")) |
|
556 { |
|
557 // Failed to open sharable file |
|
558 return; |
|
559 } |
|
560 |
|
561 // Create request for the sharable file |
|
562 XQAiwreqiuest req = mAiwMgr.create(sf); |
|
563 if (!req) |
|
564 { |
|
565 // No viewer app found for the file |
|
566 // As we opened the handle, we need to close it ! |
|
567 sf.close(); |
|
568 return; |
|
569 } |
|
570 // By default operation is "view(XQSharableFile)" |
|
571 |
|
572 // Set function parameters |
|
573 // Not only one sharable handle supported, otherwise upon send EArgumentError error occurs |
|
574 QList<QVariant> args; |
|
575 args << qVariantFromValue(sf); |
|
576 req->setArguments(args); |
|
577 |
|
578 // Send the request |
|
579 bool res = request.send(); |
|
580 if (!res) |
|
581 { |
|
582 // Request failed. |
|
583 int error = request->lastError(); |
|
584 // Handle error |
|
585 } |
|
586 |
|
587 // As we opened the handle, we need to close it ! |
|
588 sf.close(); |
|
589 |
|
590 // If making multiple requests to same service, you can save the request as member variable |
|
591 // In this example all done. |
|
592 delete request; |
|
593 \endcode |
|
594 |
|
595 <b> Create interface action </b> \n |
|
596 One interface XML may offer one action to be displayed by client application. |
|
597 See the "examples/appmgrclient" and "examples/hbserviceprovider" included in the QtHighway release. |
|
598 |
|
599 \code |
|
600 HbAction* ShareUiPrivate::fetchServiceAction(XQAiwInterfaceDescriptor interfaceDescriptor) |
|
601 { |
|
602 QDEBUG_WRITE("ShareUiPrivate::fetchServiceAction start"); |
|
603 // create the request for each descriptor. |
|
604 |
|
605 XQAiwRequest* request = mAppManager.create(interfaceDescriptor,SELECT_OP,false); |
|
606 QAction action = request->createAction()); |
|
607 if (!action) |
|
608 return 0; |
|
609 |
|
610 // if Orbit widgets do not support QAction |
|
611 // Need to convert QAction to HbAction first |
|
612 HbAction* hbAction = convertAction(action); |
|
613 if(hbAction) |
|
614 { |
|
615 // Connect triggered signals to enable the request to emit triggered |
|
616 connect(hbAction, SIGNAL(triggered()), action, SIGNAL(triggered())); |
|
617 |
|
618 // connect the request's triggered action to the slot in app |
|
619 connect(request, SIGNAL(triggered()), this, SLOT(onTriggered())); |
|
620 } |
|
621 |
|
622 return hbAction; |
|
623 } |
|
624 \endcode |
|
625 |
|
626 In service provider side you need to have the following entries in XML to be converted to QAction by the create: |
|
627 |
|
628 \code |
|
629 <interface> |
|
630 <name>Dialer></name> |
|
631 <version=1.0</version> |
|
632 <description>Dial interface</description> |
|
633 <customproperty key="aiw_action_text_file">hbserviceprovider</customproperty> |
|
634 <customproperty key="aiw_action_text">txt_aiw_action_text</customproperty> |
|
635 </interface> |
|
636 \endcode |
|
637 */ |
|
638 |
|
639 /*! |
|
640 \fn void XQServiceProvider::returnValueDelivered() |
|
641 |
|
642 This signal is emitted when asynchronous request has been completed and its |
|
643 return value has been delivered to the service client. |
|
644 */ |
|
645 |
|
646 /*! |
|
647 \fn void XQServiceProvider::clientDisconnected() |
|
648 |
|
649 This signal is emitted if client accessing a service application terminates. |
|
650 The counterpart in client side (when service application terminates) is |
|
651 the error XQService::EConnectionClosed. |
|
652 */ |
|
653 |
|
654 /*! |
|
655 Construct a remote service object for \a service and attach it to \a parent. |
|
656 \param service Defines the full service name that is implemented. |
|
657 The full service name is: |
|
658 - The name of the service from the service configuration file |
|
659 - Character *.* (dot) |
|
660 - The name of the interface from the service configuration file |
|
661 \param parent Parent of this QObject |
|
662 */ |
|
663 XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent ) |
|
664 : QObject( parent ) |
|
665 { |
|
666 XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider"); |
|
667 XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service)); |
|
668 m_data = new XQServiceProvider_Private(service); |
|
669 connect(m_data->m_adaptor, SIGNAL(returnValueDelivered()), this, SIGNAL(returnValueDelivered())); |
|
670 connect(m_data->m_adaptor, SIGNAL(clientDisconnected()), this, SIGNAL(clientDisconnected())); |
|
671 } |
|
672 |
|
673 /*! |
|
674 Destroys this service handling object. |
|
675 */ |
|
676 XQServiceProvider::~XQServiceProvider() |
|
677 { |
|
678 XQSERVICE_DEBUG_PRINT("XQServiceProvider::~XQServiceProvider"); |
|
679 if (m_data) |
|
680 delete m_data; |
|
681 } |
|
682 |
|
683 |
|
684 void XQServiceProvider::SetPlugin(QObject* impl_plugin) |
|
685 { |
|
686 m_data->plugin=impl_plugin; |
|
687 } |
|
688 |
|
689 |
|
690 /*! |
|
691 Publishes all slots on this object within subclasses of XQServiceProvider. |
|
692 This is typically called from a subclass constructor. |
|
693 */ |
|
694 void XQServiceProvider::publishAll() |
|
695 { |
|
696 XQSERVICE_DEBUG_PRINT("XQServiceProvider::publishAll"); |
|
697 if (!m_data->plugin) { |
|
698 m_data->m_adaptor->publishAll(this,XQServiceProvider::staticMetaObject.methodCount(),XQServiceAdaptor::Slots); |
|
699 } |
|
700 else { |
|
701 m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots); |
|
702 } |
|
703 } |
|
704 |
|
705 /*! |
|
706 Sets current request to asynchronous mode so that provider can complete the |
|
707 request later via the completeRequest() call. |
|
708 \return Request ID which shall be used in the completeRequest() call. |
|
709 \note There can be several clients accessing the same service at the same time. Avoid saving |
|
710 the index to XQServiceProvider instance as member variable as when another new request |
|
711 comes in, it will have different index and you will potentially override the index of |
|
712 the first request. You should ensure the completeRequest() gets the correct index e.g. |
|
713 by attaching the index as user data to data object maintain a map of indexes based on |
|
714 some key. |
|
715 */ |
|
716 int XQServiceProvider::setCurrentRequestAsync() |
|
717 { |
|
718 XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync"); |
|
719 return m_data->m_adaptor->setCurrentRequestAsync(); |
|
720 } |
|
721 |
|
722 /*! |
|
723 \fn bool XQServiceProvider::completeRequest(int index, const T& retValue) |
|
724 |
|
725 Completes asynchronous request. |
|
726 \param index Defines the index of the asynchronous request to complete. |
|
727 \param retValue defines the return value for the request. |
|
728 \return true if request could be completed successfully, otherwise false. |
|
729 \sa completeRequest() |
|
730 */ |
|
731 |
|
732 /*! |
|
733 Completes the asynchronous request with the given value |
|
734 \param index Request ID got from the setCurrentRequestAsync call. |
|
735 \param retValue Returned value. |
|
736 \return true on success, false if index points to non-existing request. |
|
737 \note <b>You need to check the return value. </b> |
|
738 If false it means connection to client has been lost and the complete will not ever succeed. |
|
739 So if you have e.g. a code that quits application using the ReturnValueDelived signal only, |
|
740 that signal will never be emitted as request can not be completed. |
|
741 */ |
|
742 bool XQServiceProvider::completeRequest(int index, const QVariant& retValue) |
|
743 { |
|
744 XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest"); |
|
745 XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString())); |
|
746 return m_data->m_adaptor->completeRequest(index, retValue); |
|
747 } |
|
748 |
|
749 /*! |
|
750 Return additional request information attached to request |
|
751 \return Request info. |
|
752 */ |
|
753 XQRequestInfo XQServiceProvider::requestInfo() const |
|
754 { |
|
755 return m_data->m_adaptor->requestInfo(); |
|
756 } |
|
757 |
|
758 #include "xqserviceprovider.moc" |