Home · All Classes · Grouped Classes · Annotated · Functions

Qtopia Data Linking (QDL)

Introduction

Qtopia Data Linking (QDL) provides an API to associate data items across applications. A QDLLink is conceptually the same as an ordinary anchor on a webpage or as information which uniquely references an object in the same application, or another Qtopia application. When the user clicks the link the referenced object is accessed. For example, using QDL a user can create a meeting event in Calendar and a link to each person attending the meeting from Contacts. When the event is viewed, hypertext links appear for each linked contact. Activating a link sends a message to the Contacts application to display that contact.

How it Works

The linking process begins when the user edits a QDL enabled text field. These text fields are called the client in QDL and interface through an associated QDLEditClient object for QDL operations.

The user selects an Insert Link context menu option in the text field which is connected to the {QDLEditClient::requestLink()} slot. This displays a dialog listing all applications providing a QDL service, known as QDL sources. The user then selects an application which contains the data item they wish to link to.

Then a request for links is made with Qtopia Data Sharing (QDS) to the selected source. Typically, the source application will present the user with a list of items available for linking and the user then selects the desired items from the list. However, the source may carry out any specific processing required to determine the set of links.

Once a source has determined the items to be linked, it creates links for all of the items and sends them back to the client. The client receives the links and inserts them into the text field.

Links are edited and viewed as hypertext anchors. The links work like links on a standard webpage - clicking them accesses the object they refer to.

QDL Clients

The core functionality for a QDL client is provided in the QDLClient class. QDLClient manages the client's QDLLinks, allows QDLLinks to be requested from a QDL source and to activate a QDLLink on a QDL source.

To make the editing and manipulation of QDLLinks in rich-text documents easier QDLEditClient and QDLBrowserClient can be used. QDLEditClient is used when a QDL enabled rich-text document is being created with a QTextEdit widget, and QDLBrowserClient is used when a QDL enabled rich-text document is to be displayed using a QTextBrowser widget.

Editing

To enable QDL on a QTextEdit widget you create a QDLEditClient object and associate it with the QTextEdit widget. The QDLEditClient is given a unique name to help identify its links during activation, loading and saving.

    QTextEdit* txtNote = new QTextEdit( this );
    QDLEditClient* txtNoteQDLClient = new QDLEditClient( txtNote, "QDL Example" );

To request a link from a QDL source QDLEditClient::requestLinks() is called. For Qtopia Phone Edition a "Insert Link" action can be added to the context menu of the QTextEdit widget which is connected to this slot, this is done using QDLEditWidget::setupStandardContextMenu().

    txtNoteQDLClient->requestLinks();

When the creation of the the rich-text document has finished, the links and the text need to be saved. The links for all QDL clients in the widget can be saved using QDL::saveLinks() as in the example below, or for an individual QDL client using QDLClient::saveLinks().

    QString links;
    QDL::saveLinks( links, QDL::clients( this ) );
    saveLinksToFile( links );
    saveTextToFile( txtNote->toHtml() );

When the client is finished with the QDLLinks they must be removed. This can be done by calling QDLClient::clear() for each QDL client in the group or calling QDL::releaseLinks() for the entire QDL client group.

Browsing

QDLBrowserClient subclasses QTextBrowser and handles the display and activation of QDLLinks in a rich-text document. QDLBrowserClient can be used directly, or subclassed as in the example below. The QDLLinks for the client should be loaded into QDLBrowserClient, and the text should be set using QTextBrowser::setHtml(). Then QDLBrowserClient::verifyLinks() can be used to check the correctness of the QDLLinks in the widget's text.

    class ExampleBrowser : public QDLBrowserClient
    {
        Q_OBJECT;

    public:
        ExampleBrowser( QWidget *parent );

        void init();

    private:
        QString loadLinksFromFile();
        QString loadTextFromFile();
    }

    ExampleBrowser::ExampleBrowser( QWidget *parent )
    :   QDLBrowserClient( parent, "QDL Example" )
    {
        init();
    }

    void ExampleBrowser::init()
    {
        QDLBrowserClient::loadLinks( loadLinksFromFile() );
        setHtml( loadTextFromFile() );
        QDLBrowserClient::verifyLinks();
    }

Security Policy

For devices which use SXE the application's project file must including qdl and qds in the package domain.

QDL Sources

A QDL source is any Qtopia service which provides QDS services for QDL link requests and activation. Naturally the Qtopia service will be part of an application which provides data items which are of interest to other applications, such as contacts, appointment or tasks. An example Qtopia service class is provided below.

    class MyQdlService : public QtopiaAbstractService
    {
    public slots:
        ...
        void activateLink( const QDSActionRequest& request );
        void requestLinks( const QDSActionRequest& request );
        ...

    private:
        QDSData dataItemToQDLLink( DataItem data );
    }

As the QDL is implemented on top of QDS, a QDS service file needs to be defined. Refer to Qtopia Data Sharing for details.

Link Requests

For link requests the name of the service slot is not important, but the QDS service for link requests must have a request data type of "text/x-qstring", a response data type of "x-link/x-qlist-qdsdata" (as returned by QDLLink::listMimeType(), and the attributes must contain "qdl" and "request". For the service class above the service file <Qtopia Runtime Prefix>/etc/MyQslService would look like the one below.

    [Translation]
    File=QtopiaServices
    Context=MyQdlService
    [requestLinks]
    RequestDataType=text/x-qstring
    ResponseDataType=x-link/x-qlist-qdsdata
    Attributes="qdl;request"
    Description[]=Request QDL links to data items
    Icon=myQdlServceIcon

The request for links is handled in an application specific manner, but the response should contain a list of QDLLinks which have been stored as QDSData objects. For requests which require user interation, a copy of the QDSActionRequest should be created at the beginning of the service slot so that the client is informed that the request is being processed.

    void MyQdlService::qdlRequestLinks( const QDSActionRequest& request )
    {
        // Copy request to inform client of processing
        QDSActionRequest processingRequest( request );

        ...
        QList<DataItem> dataItems;
        // Select the data items
        ...

        // Pack each data item into a list and respond.
        QList<QDSData> links;
        foreach( DataItem dataItem, dataItems ) {
            links.push_back( dataItemToQDLLink( dataItem ) );
        }

        QByteArray array;
        {
            QDataStream ds( &array, QIODevice::WriteOnly );
            ds << links;
        }

        processingRequest.respond( QDSData( array, QDLLink::listMimeType() ) );
    }

Link Activation

For link activation the name of the service slot is not important, but the QDS service for link activation must have a request data type of "x-link/x-qdllink" (as returned by QDLLink::mimeType(), have no response data type, and the attributes must contain "qdl" and "activate". For the service class above the service file <Qtopia Runtime Prefix>/etc/MyQslService would look like the one below.

    [Translation]
    File=QtopiaServices
    Context=MyQdlService
    [requestLinks]
    RequestDataType=text/x-qstring
    ResponseDataType=x-link/x-qlist-qdsdata
    Attributes="qdl;request"
    Description[]=Request QDL links to data items
    Icon=myQdlServceIcon
    [activateLink]
    RequestDataType=x-link/x-qdllink
    ResponseDataType=
    Attributes="qdl;activate"
    Description[]=Activate a QDL link to a data item
    Icon=myQdlServceIcon

The activation of links is handled in an application specific manner, an example is provided below.

    void MyQdlService::qdlActivateLink( const QDSActionRequest& request )
    {
        // Grab the link from the request and check that is one of ours
        QDLLink link( request.requestData() );
        if ( link.service() != "MyQdlService" ) {
            QDSActionRequest( request ).respond( "Link doesn't belong to MyQdlService" );
            return;
        }

        const QByteArray data = link.data();
        QDataStream refStream( data );

        ...
        QString error;
        // Use the data in refStream to activate the data item
        // If an error occurs set the error string
        ...

        if ( error.isEmpty() ) {
            QDSActionRequest( request ).respond();
        } else {
            QDSActionRequest( request ).respond( error );
        }
    }

Storing the Link

Typically only one QDLLink should be generated for each data item. This is possible as QDS allows the QDLLinks to be shared across a number of QDL clients, and enables the QDLLink information to be updated as the data item changes. If the data item is removed, the QDLLink stored in the QDS data store can be broken to inform QDL clients that the data item no longer exists, and attempted activation will fail.

To make this possible the QDL source should store the QDSData for the QDLLink and hold onto the key. Then when another request for a link to a data item is made the same QDSData object can be used. In the request example above the dataItemToQDLLink() method would look something like the code below:

    QDSData MyQdlService::dataItemToQDLLink( DataItem data );
    {
        if ( !data.isValid() )
            return QDSData();

        // Check if we need to create the QDLLink
        QString keyString = data.getField( QDL::SOURCE_DATA_KEY );
        if ( keyString.isEmpty() ||
             !QDSData( QLocalUniqueId( keyString ) ).isValid() ) {
            // Creating QDLLink
            QByteArray dataRef;
            QDataStream refStream( &dataRef, QIODevice::WriteOnly );
            refStream << data.uid();

            QDLLink link( "MyQdlService",
                          dataRef,
                          data.label(),
                          "myQdlServceIcon" );

            QDSData linkData = link.toQDSData();
            QLocalUniqueId key = linkData.store();
            data.setField( QDL::SOURCE_DATA_KEY, key.toString() );

            return linkData;
        }

        // Already have a link, get it from the QDSDataStore
        return QDSData( QLocalUniqueId( keyString ) );
    }

In a similar manner the information in the stored QDLLink can be updated, the example below shows how the QDLLink can be broken when the data item is deleted.

    void MyQdlService::removeDataItemQDLLink( DataItem data )
    {
        if ( !data.isValid() )
            return QDSData();

        // Check if the QDLLink is stored
        QString keyString = data.getField( QDL::SOURCE_DATA_KEY );
        if ( key.isEmpty() )
            return;

        // Break the link in the QDSDataStore
        QDSData linkData = QDSData( QLocalUniqueId( key ) );
        QDLLink link( linkData );
        link.setBroken( true );
        linkData.modify( link.toQDSData().data() );

        // Now remove our reference to the link data
        linkData.remove();

        // Finally remove the stored key
        data.setField( QDL::SOURCE_DATA_KEY, QString() );
    }

Security Policy

For devices which use SXE the application's project file must including qdl and qds in the package domain. The SXE policy for the qdl package must also contain entries for the QDS services provided by the QDL support for the request and activation of QDLLinks. For the service class above the security policy would include:

    #
    [qdl]
    ...
    QCopSend/QCop/QPE/Application/myserviceapp/MyQdlService::requestLinks(QDSActionRequest)
    QCopSend/QCop/QPE/Application/myserviceapp/MyQdlService::activateLink(QDSActionRequest)
    ...


Copyright © 2008 Nokia Trademarks
Qtopia 4.3.3