messagingapp/msgui/unifiedviewer/src/univieweraddresswidget.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 09:45:25 +0300
changeset 52 12db4185673b
parent 44 36f374c67aa8
child 70 a15d9966050f
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description:Custom widget derived from HbTextEdit which provides rich text
 *              processing
 *
 */

#include "univieweraddresswidget.h"

// SYSTEM INCLUDES
#include <QTextCursor>
#include <QTextBlock>
#include <QApplication>
#include <QClipboard>

#include <HbMenu>
#include <HbAction>
#include <HbTapGesture>

#include <xqservicerequest.h>
#include <xqappmgr.h>
#include <cntservicescontact.h>
#include <qtcontacts.h>
#include <xqservicerequest.h>
#include <xqaiwrequest.h>
#include "msgcontacthandler.h"

// LOCAL CONSTANTS
const QString ADDRESS_SEPARATOR("; ");
const QString ADDRESS_OPEN(" (");
const QString ADDRESS_CLOSE(")");
const QString SPACE(" ");

//localization
#define LOC_CONTACT_INFO      hbTrId("txt_messaging_menu_contact_info")
#define LOC_CALL              hbTrId("txt_common_menu_call_verb")
#define LOC_SEND_MESSAGE      hbTrId("txt_common_menu_send_message")
#define LOC_SAVE_TO_CONTACTS  hbTrId("txt_common_menu_save_to_contacts")
#define LOC_COPY              hbTrId("txt_common_menu_copy")

const QString BG_FRAME_GRAPHICS("qtg_fr_lineedit_normal");

//---------------------------------------------------------------
// UniViewerAddressWidget::UniViewerAddressWidget
// @see header file
//---------------------------------------------------------------
UniViewerAddressWidget::UniViewerAddressWidget(QGraphicsItem * parent) :
HbTextEdit(parent),
mCursorPos(-1)
{
    this->setReadOnly(true);    
    this->setScrollable(false);
    this->setFlag(QGraphicsItem::ItemIsFocusable,false);
    this->setCursorVisibility(Hb::TextCursorHidden);
    this->setBackgroundItem(0);   

    HbFontSpec fontSpec(HbFontSpec::Secondary);
    QFont font = fontSpec.font();
    this->setFont(font);

    mFormatNormal.setForeground(palette().link());
    mFormatNormal.setBackground(Qt::transparent);

    mFormatHighlight.setBackground(palette().highlight());
    mFormatHighlight.setForeground(palette().highlightedText());

    connect(this, SIGNAL(aboutToShowContextMenu(HbMenu*,QPointF)),
            this, SLOT(aboutToShowContextMenu(HbMenu*,QPointF)));
}

//---------------------------------------------------------------
// UniViewerAddressWidget::~UniViewerAddressWidget
// @see header file
//---------------------------------------------------------------
UniViewerAddressWidget::~UniViewerAddressWidget()
{
}

//---------------------------------------------------------------
//UniViewerAddressWidget :: gestureEvent
// @see header file
//---------------------------------------------------------------
void UniViewerAddressWidget::gestureEvent(QGestureEvent* event)
{
    //handle gesture to highlight and dehighlight find item.
    
    if(HbTapGesture *tap = qobject_cast<HbTapGesture*>(event->gesture(Qt::TapGesture)))
    {
        //capturing gesture position, and map to local co-ordinates.
        QPointF pos = mapFromScene(tap->scenePosition());
        
        switch (tap->state()) 
        {
            case Qt::GestureStarted:
            {
                //highlight find item.
                QTextDocument* doc = this->document();
                mCursorPos = doc->documentLayout()->hitTest(pos, Qt::ExactHit);
                highlightText(true);
                break;
            }  
            
            case Qt::GestureFinished:
            {
                if (HbTapGesture::Tap == tap->tapStyleHint()) 
                {
                    //gesture is finshed dehighlight text.
                    highlightText(false);
                    
                    QString anchor = this->anchorAt(pos);
                    
                    //do short tap action.
                    if (!anchor.isEmpty() && !this->textCursor().hasSelection())
                    {
                        shortTapAction(anchor,tap->scenePosition());
                    }
                }
                break;
            }
            
            case Qt::GestureCanceled:
            {
                //gesture is canceled due to pan or swipe, dehighlight text.
                if (HbTapGesture::Tap == tap->tapStyleHint()) 
                {
                highlightText(false);
                break;
                }
            }
            default:
                break;
        }
        
        event->accept();
    }
    else
    {
        event->ignore();
    }
    
    //passing gesture event to base class.
    HbTextEdit::gestureEvent(event);
}


//----------------------------------------------------------------------------
// UniViewerAddressWidget::populate
// @see header file
//----------------------------------------------------------------------------
void UniViewerAddressWidget::populate(const QString &label,
                                      const QString &address,
                                      const QString &alias)
{
    QString labelText = label;
    labelText.trimmed();
    labelText += SPACE;
    
    //Font.
    HbFontSpec fontSpec(HbFontSpec::Secondary);
    qreal fontHeight = 0.0;
    style()->parameter("hb-param-text-height-tiny", fontHeight);
    fontSpec.setTextHeight(fontHeight);    
    QFont font = fontSpec.font();
    
    QTextCharFormat labelFormat;
    labelFormat.setFont(font);
    
    QTextCharFormat addressFormat;
    addressFormat.setForeground(palette().link());
    addressFormat.setFontUnderline(true);

    // Insert the label then the addresses
    QTextCursor cursor(this->textCursor());
    cursor.insertText(labelText,labelFormat);
    
    QString address1 = QString();
    if (!(alias.isEmpty()))
    {
        address1.append(alias);
        QString alias1 = QString();
        
        int totalNumbers = 0;
        MsgContactHandler::resolveContactDisplayName(
                        address,
                        alias1,
                        totalNumbers);
        if (totalNumbers > 1)
        {
            address1.append(ADDRESS_OPEN);
            address1.append(address);
            address1.append(ADDRESS_CLOSE);
        }
    }
    else
    {
        address1.append(address);
    }
    addressFormat.setAnchorHref(address);
    cursor.insertText(address1, addressFormat);
}

//----------------------------------------------------------------------------
// UniViewerAddressWidget::populate
// @see header file
//----------------------------------------------------------------------------
void UniViewerAddressWidget::populate(const QString &label,
                                      ConvergedMessageAddressList addressList)
{
    QString labelText = label;
    labelText.trimmed();
    labelText += SPACE;
    
    //Font.
    HbFontSpec fontSpec(HbFontSpec::Secondary);
    qreal fontHeight = 0.0;
    style()->parameter("hb-param-text-height-tiny", fontHeight);
    fontSpec.setTextHeight(fontHeight);    
    QFont font = fontSpec.font();
    
    QTextCharFormat labelFormat;
    labelFormat.setFont(font);
    
    QTextCharFormat defaultFormat;
    defaultFormat.setForeground(palette().link());

    QTextCharFormat addressFormat;
    addressFormat.setForeground(palette().link());
    addressFormat.setFontUnderline(true);

    // Insert the label then the addresses
    QTextCursor cursor(this->document());
    cursor.insertText(labelText,labelFormat);

    int addressCount = addressList.count();

    for (int i = 0; i < addressCount; ++i)
    {

        QString address = QString();
        if (! (addressList[i]->alias().isEmpty()))
        {
            address.append(addressList[i]->alias());
            QString alias = QString();
            
            int totalNumbers = 0;
            MsgContactHandler::resolveContactDisplayName(
                            addressList[i]->address(),
                            alias,
                            totalNumbers);
            if (totalNumbers > 1)
            {
                address.append(ADDRESS_OPEN);
                address.append(addressList[i]->address());
                address.append(ADDRESS_CLOSE);
            }
        }
        else
        {
            address.append(addressList[i]->address());
        }

        addressFormat.setAnchorHref(addressList[i]->address());
        cursor.insertText(address, addressFormat);

        if (addressCount - 1 != i)
        {
            cursor.insertText(ADDRESS_SEPARATOR, defaultFormat);
        }
        
    }
}

//----------------------------------------------------------------------------
// UniViewerAddressWidget::clearContent
// @see header file
//----------------------------------------------------------------------------
void UniViewerAddressWidget::clearContent()
{
    this->document()->clear();
}

//----------------------------------------------------------------------------
// UniViewerAddressWidget::menuClosed
// @see header file
//----------------------------------------------------------------------------
void UniViewerAddressWidget::menuClosed()
{
    highlightText(false);
}

//----------------------------------------------------------------------------
// UniViewerAddressWidget::highlightText
// @see header file
//----------------------------------------------------------------------------
void UniViewerAddressWidget::highlightText(bool highlight)
{
    QTextBlock textBlock = this->document()->findBlock(mCursorPos);

    QTextBlock::iterator it;

    for (it = textBlock.begin(); !(it.atEnd()); ++it)
    {
        QTextFragment currentFragment = it.fragment();
        
        if (currentFragment.isValid() && currentFragment.contains(mCursorPos)
            && currentFragment.charFormat().fontUnderline())
        {
            int start = currentFragment.position();
            int length = currentFragment.length();

            QTextCursor cursor = this->textCursor();
            cursor.clearSelection();
            cursor.setPosition(start);
            cursor.setPosition(start + length,QTextCursor::KeepAnchor);

            if(highlight)
            {
                cursor.mergeCharFormat(mFormatHighlight);
            }
            else
            {
                cursor.mergeCharFormat(mFormatNormal);
            }

            cursor.clearSelection();
            break;
        }
    }
}

void UniViewerAddressWidget::aboutToShowContextMenu(HbMenu *contextMenu, const QPointF &pos)
{
    //remove default actions.
    contextMenu->clearActions();
    
    // Check if there is an anchor at this pos
    QString  anchor = this->anchorAt(pos);

    if(!anchor.isEmpty() && !this->textCursor().hasSelection())
    {
        populateMenu(contextMenu,anchor);
    }
}

void UniViewerAddressWidget::populateMenu(HbMenu* contextMenu,const QString& data)
{
    HbAction* action = NULL;

    int contactId = MsgContactHandler::resolveContactDisplayName(
                                 data, 
                                 QContactPhoneNumber::DefinitionName,
                                 QContactPhoneNumber::FieldNumber); 
    
    if(contactId > 0)
    {
        action = contextMenu->addAction(LOC_CONTACT_INFO, this, SLOT(openContactInfo()));
        action->setData(data);
    }
    else
    {
        action = contextMenu->addAction(LOC_SAVE_TO_CONTACTS, this, SLOT(saveToContacts()));
        action->setData(data);  
    }

    action = contextMenu->addAction(LOC_CALL, this, SLOT(call()));
    action->setData(data);

    action = contextMenu->addAction(LOC_SEND_MESSAGE, this, SLOT(sendMessage()));
    action->setData(data);

    action = contextMenu->addAction(LOC_COPY, this, SLOT(copyToClipboard()));
    action->setData(data);
    
    connect(contextMenu,SIGNAL(aboutToClose()),this,SLOT(menuClosed())); 
}

void UniViewerAddressWidget::shortTapAction(QString anchor,const QPointF& pos)
{
    HbAction action;
    action.setData(anchor);


    int contactId = MsgContactHandler::resolveContactDisplayName(
        anchor, 
        QContactPhoneNumber::DefinitionName,
        QContactPhoneNumber::FieldNumber);        

    if(contactId > 0 )
    {
        //if resolved conatct open contact card 
        connect(&action,SIGNAL(triggered()),this,SLOT(openContactInfo()));
    }
    else
    {
        //unresolved contact show popup.  
        highlightText(true);

        HbMenu* contextMenu = new HbMenu();
        contextMenu->setDismissPolicy(HbPopup::TapAnywhere);
        contextMenu->setAttribute(Qt::WA_DeleteOnClose, true);
        contextMenu->setPreferredPos(pos); 

        populateMenu(contextMenu,anchor);
        
        contextMenu->show();
    }

    action.trigger();
}

void UniViewerAddressWidget::copyToClipboard()
{
    HbAction* action = qobject_cast<HbAction*>(sender());

    if(action)
    {
        QMimeData* data = new QMimeData();
        QString str = action->data().toString();
        data->setText(str);
        QApplication::clipboard()->setMimeData(data);
    }
}

void UniViewerAddressWidget::call()
{
    HbAction* action = qobject_cast<HbAction*>(sender());

    if(action)
    {
        QString phoneNumber = action->data().toString();
        
        //invoke dialer service and pass phoneNumber.        
        QString serviceName("com.nokia.symbian.ICallDial");
        QString operation("dial(QString)");
        
        XQServiceRequest* serviceRequest = new XQServiceRequest(serviceName,operation,false);
        
        connect(serviceRequest, SIGNAL(requestCompleted(QVariant)),
                this, SLOT(onServiceRequestCompleted()));
        
        connect(serviceRequest, SIGNAL(requestError(int)),
                this, SLOT(onServiceRequestCompleted()));
        
        *serviceRequest << phoneNumber;
        serviceRequest->send();
    }
}

void UniViewerAddressWidget::onServiceRequestCompleted()
    {
    //service request is now complete. delete it.    
    XQServiceRequest* request = qobject_cast<XQServiceRequest*>(sender());
    
    if(request)
        {
        delete request;
        }
    }


void UniViewerAddressWidget::openContactInfo()
{
    HbAction* action = qobject_cast<HbAction*>(sender());
    
    if(action)
    {
        QList<QVariant> args;
        QString operation;
        
        QString data = action->data().toString();        
    
        int contactId = MsgContactHandler::resolveContactDisplayName(
                data,
                QContactPhoneNumber::DefinitionName,
                QContactPhoneNumber::FieldNumber);

        // if contact is unresolved on phone number field
        // then, try resolving it on email address field
        if(contactId <= 0)
        {
            contactId = MsgContactHandler::resolveContactDisplayName(
                data,
                QContactEmailAddress::DefinitionName,
                QContactEmailAddress::FieldEmailAddress);
        }

        if(contactId > 0)
        {
            //open contact card
            operation = QString("open(int)");
            args << contactId;
        }
        else
        {
            //save to contacts with phone number field prefilled.

            operation = QString("editCreateNew(QString,QString)");
            QString type = QContactPhoneNumber::DefinitionName;

            args << type;
            args << data;
        }
        
        //service stuff.
        QString serviceName("com.nokia.services.phonebookservices");
     
        XQAiwRequest* request;
        XQApplicationManager appManager;
        request = appManager.create(serviceName, "Fetch", operation, true); // embedded
        if ( request == NULL )
            {
            return;       
            }

        // Result handlers
        connect (request, SIGNAL(requestOk(const QVariant&)), 
            this, SLOT(handleOk(const QVariant&)));
        connect (request, SIGNAL(requestError(const QVariant&)), 
            this, SLOT(handleError(const QVariant&)));
        
        request->setArguments(args);
        request->send();
        delete request;
    }
}

void UniViewerAddressWidget::handleOk(const QVariant& result)
    {
    Q_UNUSED(result)
    }

void UniViewerAddressWidget::handleError(int errorCode, const QString& errorMessage)
    {
    Q_UNUSED(errorMessage)
    Q_UNUSED(errorCode)
    }

void UniViewerAddressWidget::saveToContacts()
{
    openContactInfo();
}

void UniViewerAddressWidget::sendMessage()
{
    HbAction* action = qobject_cast<HbAction*>(sender());

    if(action)
    {
        QString phoneNumber = action->data().toString();
        QString alias;

        QTextBlock textBlock = this->document()->findBlock(mCursorPos);

        QTextBlock::iterator it;

        for (it = textBlock.begin(); !(it.atEnd()); ++it)
        {
            QTextFragment currentFragment = it.fragment();

            if (currentFragment.isValid() && currentFragment.contains(mCursorPos)
                && currentFragment.charFormat().fontUnderline())
            {
                QString txt = currentFragment.text();
                if(txt != phoneNumber)
                {
                    alias = txt;  
                }
                break;
            }
        }
        

        //invoke editor & pass phoneNumber.
        emit sendMessage(phoneNumber,alias);
    }
}

// EOF