qthighway/xqservice/src/xqserviceprovider.cpp
branchRCL_3
changeset 22 5d007b20cfd0
equal deleted inserted replaced
21:885c2596c964 22:5d007b20cfd0
       
     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&param1=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"