28 #include <xqserviceadaptor.h> |
28 #include <xqserviceadaptor.h> |
29 //#include <xqserviceservice.h> |
29 //#include <xqserviceservice.h> |
30 #include <xqserviceutil.h> |
30 #include <xqserviceutil.h> |
31 |
31 |
32 /*! |
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 /*! |
33 \class XQServiceProvider |
106 \class XQServiceProvider |
34 \inpublicgroup QtBaseModule |
107 \inpublicgroup QtBaseModule |
35 |
108 |
36 \brief The XQServiceProvider class provides an interface to messages on a XQService service |
109 \brief The XQServiceProvider class provides an interface to messages on a XQService service |
37 which simplifies remote slot invocations |
110 which simplifies remote slot invocations |
38 |
111 |
39 Service messages consist of a service name, a message name, and a list of parameter values. |
112 Service messages consist of a service name, a message name, and a list of parameter values. |
40 Qt extension extension dispatches service messages to the applications associated with the service |
113 Qt extension dispatches service messages to the applications associated with the service |
41 name, on the application's \c{QPE/Application/appname} channel, where |
114 name, on the application's \c{QPE/Application/appname} channel, where |
42 \c{appname} is the application's name. |
115 \c{appname} is the application's name. |
43 |
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 |
44 The use of XQServiceProvider will be demonstrated using the \c{Time} |
325 The use of XQServiceProvider will be demonstrated using the \c{Time} |
45 service. This has a single message called \c{editTime()} which asks |
326 service. This has a single message called \c{editTime()} which asks |
46 the service to pop up a dialog allowing the user to edit the current time. |
327 the service to pop up a dialog allowing the user to edit the current time. |
47 |
|
48 \code |
328 \code |
49 class TimeService : public XQServiceProvider |
329 class TimeService : public XQServiceProvider |
50 { |
330 { |
51 Q_OBJECT |
331 Q_OBJECT |
52 public: |
332 public: |
72 \code |
352 \code |
73 XQServiceRequest req( "Time", "editTime()" ); |
353 XQServiceRequest req( "Time", "editTime()" ); |
74 req << QTime::currentTime(); |
354 req << QTime::currentTime(); |
75 req.send(); |
355 req.send(); |
76 \endcode |
356 \endcode |
77 |
357 |
78 */ |
358 <b>URI viewer</b> \n |
79 |
359 This is a simple example for implementing out-of-process scheme handlers. |
80 class ServiceAdaptorProxy : public XQServiceAdaptor |
360 - "http", "https" and are handled via standard QDesktopServices::openUrl() function. |
81 { |
361 This is fire-and-forget launch. The options are ignored and no control and signals available after the launch. |
82 Q_OBJECT |
362 - "appto" is routed to Activity Manager for opening the attached activity. |
83 |
363 This is fire-and-forget launch. The options are ignored and no control and signals available after the launch. |
84 public: |
364 - The "file" scheme is handled as the QFile based create below. |
85 ServiceAdaptorProxy(const QString &channel, QObject *parent=0); |
365 So the com.nokia.symbian.IFileView interface is applied as for the QFile. |
86 virtual ~ServiceAdaptorProxy() ; |
366 |
87 |
367 Service application needs to publish support for: |
88 QString memberToMessage( const QByteArray& member ); |
368 - The common interface "com.nokia.symbian.IUriView", and |
89 }; |
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) |
90 |
370 - The slot "view(QString)" to view the URI |
91 ServiceAdaptorProxy::ServiceAdaptorProxy(const QString &channel, QObject *parent) : |
371 |
92 XQServiceAdaptor(channel, parent) |
372 \code |
93 { |
373 <?xml version="1.0" encoding="utf-8" ?> |
94 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::ServiceAdaptorProxy"); |
374 <service> |
95 XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel)); |
375 <name>serviceapp</name> |
96 } |
376 <filepath>No path</filepath> |
97 |
377 <description>Test service</description> |
98 ServiceAdaptorProxy::~ServiceAdaptorProxy() |
378 <interface> |
99 { |
379 <name>com.nokia.symbian.IUriView</name> |
100 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::~ServiceAdaptorProxy"); |
380 <version>1.0</version> |
101 } |
381 <description>Interface for showing URIs</description> |
102 |
382 <customproperty key="schemes">testto</customproperty> |
103 QString ServiceAdaptorProxy::memberToMessage( const QByteArray& member ) |
383 </interface> |
104 { |
384 </service> |
105 XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::memberToMessage"); |
385 \endcode |
106 XQSERVICE_DEBUG_PRINT("member: %s", member.constData()); |
386 |
107 // TO BE CHECKED |
387 An service application that offers support for a scheme implements the common "UriService" with the pre-defined "view" slot: |
108 // return m_channel + "::" + XQServiceAdaptor::memberToMessage( member ); |
388 |
109 return XQServiceAdaptor::memberToMessage( member ); |
389 \code |
110 } |
390 class UriService : public XQServiceProvider |
111 |
391 { |
112 class XQServiceProvider_Private |
392 Q_OBJECT |
113 { |
393 public: |
114 public: |
394 UriService( ServiceApp *parent = 0 ); |
115 XQServiceProvider_Private(const QString &service); |
395 ~UriService(); |
116 |
396 bool asyncAnswer() {return mAsyncAnswer;} |
117 ~XQServiceProvider_Private(); |
397 void complete(bool ok); |
118 |
398 |
119 XQServiceAdaptor *m_adaptor; |
399 public slots: |
120 |
400 bool view(const QString& uri); |
121 QString m_service; |
401 |
122 bool m_publishAllCalled; |
402 private slots: |
123 QObject* plugin; |
403 void handleClientDisconnect(); |
124 }; |
404 |
125 |
405 private: |
126 XQServiceProvider_Private::XQServiceProvider_Private(const QString &service) : |
406 ServiceApp* mServiceApp; |
127 m_adaptor(NULL), |
407 bool mAsyncAnswer; |
128 m_service(service), |
408 int mAsyncReqId; |
129 m_publishAllCalled(false), |
409 bool mRetValue; |
130 plugin(NULL) |
410 }; |
131 { |
411 \endcode |
132 XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::XQServiceProvider_Private"); |
412 |
133 XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service)); |
413 Client application accesses the service via the URI: |
134 m_adaptor = new ServiceAdaptorProxy(service); |
414 |
135 } |
415 \code |
136 |
416 // Assume in example we have own scheme "testo" but this can be applied to |
137 XQServiceProvider_Private::~XQServiceProvider_Private() |
417 // "mailto", etc. standard schemes. |
138 { |
418 // |
139 XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::~XQServiceProvider_Private"); |
419 // (As mentioned in the documentation, some schemes are CURRENTLY handled specially, |
140 delete m_adaptor; |
420 // like "http" scheme uses QDesktopServices::openUrl). |
141 } |
421 // |
142 |
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 */ |
143 |
653 |
144 /*! |
654 /*! |
145 Construct a remote service object for \a service and attach it to \a parent. |
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 |
146 */ |
662 */ |
147 XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent ) |
663 XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent ) |
148 : QObject( parent ) |
664 : QObject( parent ) |
149 { |
665 { |
150 XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider"); |
666 XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider"); |
185 m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots); |
701 m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots); |
186 } |
702 } |
187 } |
703 } |
188 |
704 |
189 /*! |
705 /*! |
190 * Sets current request to asynchronous mode so that provider can complete the |
706 Sets current request to asynchronous mode so that provider can complete the |
191 * request later via the completeRequest() call. |
707 request later via the completeRequest() call. |
192 * \return Request ID which shall be used in 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. |
193 */ |
715 */ |
194 int XQServiceProvider::setCurrentRequestAsync() |
716 int XQServiceProvider::setCurrentRequestAsync() |
195 { |
717 { |
196 XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync"); |
718 XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync"); |
197 return m_data->m_adaptor->setCurrentRequestAsync(); |
719 return m_data->m_adaptor->setCurrentRequestAsync(); |
198 } |
720 } |
199 |
721 |
200 /*! |
722 /*! |
201 * Completes the asynchronous request with the given value |
723 \fn bool XQServiceProvider::completeRequest(int index, const T& retValue) |
202 * \param index Request ID got from the setCurrentRequestAsync call. |
724 |
203 * \param retValue The value |
725 Completes asynchronous request. |
204 * \return true on success, false if index points to non-existing 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. |
205 */ |
741 */ |
206 bool XQServiceProvider::completeRequest(int index, const QVariant& retValue) |
742 bool XQServiceProvider::completeRequest(int index, const QVariant& retValue) |
207 { |
743 { |
208 XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest"); |
744 XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest"); |
209 XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString())); |
745 XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString())); |
210 return m_data->m_adaptor->completeRequest(index, retValue); |
746 return m_data->m_adaptor->completeRequest(index, retValue); |
211 } |
747 } |
212 |
748 |
213 /*! |
749 /*! |
214 * Return additional request information attached to request |
750 Return additional request information attached to request |
215 * \return Request info |
751 \return Request info. |
216 */ |
752 */ |
217 XQRequestInfo XQServiceProvider::requestInfo() const |
753 XQRequestInfo XQServiceProvider::requestInfo() const |
218 { |
754 { |
219 return m_data->m_adaptor->requestInfo(); |
755 return m_data->m_adaptor->requestInfo(); |
220 } |
756 } |