phonebookui/pbkcommonui/src/cnteditview_p.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 23 Jun 2010 18:02:44 +0300
changeset 46 efe85016a067
parent 40 b46a585f6909
child 47 7cbcb2896f0e
permissions -rw-r--r--
Revision: 201023 Kit: 2010125

/*
* 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:  
*
*/

#include "cnteditview_p.h"
#include "cnteditviewlistmodel.h"
#include "cntdocumentloader.h"
#include "cntdetailpopup.h"
#include "cnteditviewheadingitem.h"
#include "cntimagelabel.h"

#include <qtcontacts.h>
#include <hbdocumentloader.h>
#include <thumbnailmanager_qt.h>
#include <hbabstractviewitem.h>
#include <hbmessagebox.h>
#include <hbgroupbox.h>
#include <hbmainwindow.h>
#include <hbview.h>
#include <hblistview.h>
#include <hbaction.h>
#include <hbmenu.h>
#include <hbframebackground.h>
#include <hbparameterlengthlimiter.h>
#include <hbdevicenotificationdialog.h>

const char *CNT_EDIT_XML = ":/xml/contacts_ev.docml";

CntEditViewPrivate::CntEditViewPrivate() :
mModel( NULL ),
mImageLabel( NULL ),
mThumbnailManager( NULL ),
mContact( NULL )
{
    mDocument = new CntDocumentLoader;
    
    bool ok;
    mDocument->load( CNT_EDIT_XML, &ok );
    if ( !ok ){
        qFatal( "Unable to load %S", CNT_EDIT_XML );
    }
    mView = static_cast<HbView*>( mDocument->findWidget("view") );
    mListView = static_cast<HbListView*>( mDocument->findWidget("listView") );
    mListView->setLayoutName("editviewlist");
    HbFrameBackground frame;
    frame.setFrameGraphicsName("qtg_fr_list_normal");
    frame.setFrameType(HbFrameDrawer::NinePieces);
    mListView->itemPrototypes().first()->setDefaultFrame(frame);
    
    mHeading = static_cast<CntEditViewHeadingItem*>( mDocument->findWidget("editViewHeading") );
    mImageLabel = static_cast<CntImageLabel*>(mDocument->findWidget("editViewImage"));
    
    mSoftkey = new HbAction(Hb::BackNaviAction, mView);
    mDiscard = static_cast<HbAction*>( mDocument->findObject("cnt:discard") );
    mDiscard->setParent(mView);

    mSave = static_cast<HbAction*>( mDocument->findObject("cnt:savecontact") );
    mSave->setParent(mView);

    mDelete = static_cast<HbAction*>( mDocument->findObject("cnt:deletecontact") );
    mDelete->setParent(mView);
    
    HbAction* add = static_cast<HbAction*>( mDocument->findObject("cnt:adddetail_options") );
    add->setParent(mView);

    connect( add, SIGNAL(triggered()), this, SLOT(addDetailItem()) );
    connect( mDelete, SIGNAL(triggered()), this, SLOT(deleteContact()) );
    connect( mDiscard, SIGNAL(triggered()), this, SLOT(discardChanges()) );
    connect( mSave, SIGNAL(triggered()), this, SLOT(saveChanges()) );
        
    connect( mSoftkey, SIGNAL(triggered()), this, SLOT(saveChanges()) );
    connect( mImageLabel, SIGNAL(iconClicked()), this, SLOT(openImageEditor()) );
    connect( mHeading, SIGNAL(textClicked()), this, SLOT(openNameEditor()) );
    connect( mHeading, SIGNAL(iconClicked()), this, SLOT(openImageEditor()) );
    connect( mListView, SIGNAL(activated(const QModelIndex&)), this, SLOT(activated(const QModelIndex&)) );
    connect( mListView, SIGNAL(longPressed(HbAbstractViewItem*,const QPointF&)), this, SLOT(longPressed(HbAbstractViewItem*,const QPointF&)) );
}

CntEditViewPrivate::~CntEditViewPrivate()
{
    mView->deleteLater();
    delete mDocument;
    delete mModel;
    delete mContact;
    
    delete mThumbnailManager;
}

void CntEditViewPrivate::setOrientation(Qt::Orientation orientation)
{
    if (orientation == Qt::Vertical) 
    {
        // reading "portrait" section
        mDocument->load( CNT_EDIT_XML, "portrait" );
    } 
    else 
    {
        // reading "landscape" section
        mDocument->load( CNT_EDIT_XML, "landscape" );
    }
}

void CntEditViewPrivate::activate( CntAbstractViewManager* aMgr, const CntViewParameters aArgs )
{
    mMgr = aMgr;
    mArgs = aArgs;
    
    if ( mView->navigationAction() != mSoftkey)
    {
        mView->setNavigationAction(mSoftkey);
    }
    HbMainWindow* window = mView->mainWindow();
    if ( window )
    {
        connect(window, SIGNAL(viewReady()), this, SLOT(setScrollPosition()) );
        connect(window, SIGNAL(orientationChanged(Qt::Orientation)), this, SLOT(setOrientation(Qt::Orientation)));
        setOrientation(window->orientation());
    }
        
    QString myCard = mArgs.value( EMyCard ).toString();
    QString selectedAction = mArgs.value( ESelectedAction ).toString();
    QVariant contact = aArgs.value( ESelectedContact );
    setSelectedContact( contact.value<QContact>() );
        
    QContactLocalId localId = mContact->localId();
    QContactManager* cm = mMgr->contactManager(SYMBIAN_BACKEND);
    QContactLocalId selfContactId = cm->selfContactId();
    mIsMyCard = ( localId == selfContactId && localId != 0 ) || myCard == "myCard";
    
    if ( mHeading )
        mHeading->setDetails( mContact, mIsMyCard );

    // if "MyCard", set slightly different heading and options menu
    if ( mIsMyCard )
    {
        mSave->setText(hbTrId("txt_phob_opt_save_my_card"));
        mDelete->setText(hbTrId("txt_phob_opt_clear_my_card"));
        HbGroupBox* groupBox = static_cast<HbGroupBox*>( mDocument->findWidget("groupBox") );
        if ( groupBox )
        {
            groupBox->setHeading(hbTrId("txt_phob_subtitle_edit_my_details"));
        }
    }

    if ( localId == 0 && !mIsMyCard )
    {
        HbMenu* menu = mView->menu();
        menu->removeAction( mDelete );
    }
    
    // don't delete contact which is "MyCard" or not saved yet or both.
    if ( mIsMyCard && (mContact->details().count() <= 4 || localId == 0) )
    {
        mDelete->setEnabled( false );
    }

    // save and discard disabled if no changes found
    if ( (*mContact) == cm->contact( mContact->localId()) )
    {
        mDiscard->setEnabled( false );
        mSave->setEnabled( false );
    }
    
    mThumbnailManager = new ThumbnailManager(this);
    mThumbnailManager->setMode(ThumbnailManager::Default);
    mThumbnailManager->setQualityPreference(ThumbnailManager::OptimizeForQuality);
    mThumbnailManager->setThumbnailSize(ThumbnailManager::ThumbnailLarge);
    
    connect( mThumbnailManager, SIGNAL(thumbnailReady(QPixmap, void*, int, int)),
            this, SLOT(thumbnailReady(QPixmap, void*, int, int)) );

    loadAvatar();
}

void CntEditViewPrivate::deactivate()
{   
}

void CntEditViewPrivate::openView(CntViewParameters& viewParams)
{
    QList<int> keys = viewParams.keys();
    for(int i = 0;i < keys.count();i++)
    {
        mArgs.insert(keys.at(i), viewParams.value(keys.at(i)));
    }
    mMgr->changeView( mArgs );
}

void CntEditViewPrivate::requestRefresh()
{
    mModel->refreshExtensionItems();
}
    
void CntEditViewPrivate::activated( const QModelIndex& aIndex )
{
    CntEditViewItem* item = mModel->itemAt( aIndex );
    QVariant type = item->data( ERoleItemType );
    if ( type == QVariant(ETypeUiExtension) )
    {
        item->activated(this);
    }
    else
    {
        // open editor view
        QVariant id = item->data( ERoleEditorViewId );
        mArgs.insert(EViewId, id.toInt());
        
        QVariant var;
        var.setValue(*mContact);
        mArgs.insert(ESelectedContact, var);
        mArgs.insert(ESelectedAction, QString() );
        mMgr->changeView( mArgs );
    }
}

void CntEditViewPrivate::longPressed( HbAbstractViewItem* aItem, const QPointF& aCoords )
{
    CntEditViewItem* item = mModel->itemAt( aItem->modelIndex() );
    QVariant type = item->data( ERoleItemType );
    
    // Ui extensions handle the long press by themselves.
    if ( type == QVariant(ETypeUiExtension) )
    {
        item->longPressed( aCoords, this );
    }
    // only detail items are able to show context specific menu
    else
    {
        HbMenu* menu = createPopup( aItem->modelIndex(), item );
        menu->setAttribute( Qt::WA_DeleteOnClose, true );
        menu->setPreferredPos( aCoords );
        menu->setModal( true );
        menu->open( this, SLOT(handleMenuAction(HbAction*)) );
    }
}

void CntEditViewPrivate::handleMenuAction( HbAction* aAction )
{
    int row = aAction->data().toInt();
    QModelIndex index = mModel->index(row, 0);
    CntEditViewItem* item = mModel->itemAt( index );
    if ( aAction )
    {
        switch ( aAction->property("menu").toInt() )  
        {
        case HbAction::EditRole:
        {
            editDetail( item );
        }
        break;
        
        case HbAction::NewRole:
        {
            addDetail( item );
        }
        break;
        
        case HbAction::DeleteRole:
        {
            removeDetail( item, index );
        }
        break;
        
        default:
            break;
        }
    }
}

void CntEditViewPrivate::addDetailItem()
{
    CntViewIdList list;
    mModel->allInUseFields( list );
    
    CntDetailPopup::selectDetail( list, this, SLOT(handleAddDetailItem(HbAction*)) );
}

void CntEditViewPrivate::handleAddDetailItem(HbAction *aAction)
{
    CntDetailPopup *popup = static_cast<CntDetailPopup*>(sender());
    
    if (popup && aAction != popup->actions().first())
    {
        int id = popup->selectedDetail();
        
        if (id != noView )
        {
            mArgs.insert(EViewId, id );

            switch ( id )
            {
            case phoneNumberEditorView:
            case emailEditorView:
            case urlEditorView:
            case noteEditorView:
                mArgs.insert( ESelectedAction, "add" );
                break;
            case addressEditorView:
            case dateEditorView:
            case companyEditorView:
            case familyDetailEditorView:
                mArgs.insert( ESelectedAction, "focus" );
                break;
            default:
                break;
            }
            QVariant var;
            var.setValue(*mContact);
            mArgs.insert(ESelectedContact, var);
            mMgr->changeView( mArgs );
        }
    }
}

void CntEditViewPrivate::deleteContact()
{
    if ( mIsMyCard )
    {
        HbMessageBox::question(hbTrId("txt_phob_dialog_remove_all_personal_data_from_my_c"), this, 
                SLOT(handleDeleteContact(HbAction*)), 
                hbTrId("txt_phob_button_clear"), 
                hbTrId("txt_common_button_cancel"));
    }
    else
    {
        QContactManager* cm = mMgr->contactManager( SYMBIAN_BACKEND );
        QString name = cm->synthesizedDisplayLabel( *mContact );
        HbMessageBox::question(HbParameterLengthLimiter(hbTrId("txt_phob_info_delete_1")).arg(name), this, SLOT(handleDeleteContact(HbAction*)), 
                hbTrId("txt_common_button_delete"), hbTrId("txt_common_button_cancel"));
    }
}

void CntEditViewPrivate::handleDeleteContact(HbAction *action)
{
    HbMessageBox *dlg = static_cast<HbMessageBox*>(sender());
    if(dlg && action == dlg->actions().first())
    {
        QContactManager* cm = mMgr->contactManager( SYMBIAN_BACKEND );

        emit contactRemoved(cm->removeContact( mContact->localId() ));
        
        mMgr->back( mArgs );
    }
}

void CntEditViewPrivate::discardChanges()
{
    emit changesDiscarded();
    
    // get a fresh one from backend.
    QContactManager* mgr = mMgr->contactManager(SYMBIAN_BACKEND);
    mContact = new QContact(mgr->contact( mContact->localId() ));
    
    QVariant var;
    var.setValue(*mContact);
    
    CntViewParameters viewParameters;
    viewParameters.insert(ESelectedContact, var);
            
    mMgr->back( viewParameters );
}

void CntEditViewPrivate::saveChanges()
{
    QContactManager* mgr = mMgr->contactManager( SYMBIAN_BACKEND );
    bool isSavedContact = mContact->localId() > 0;
    
    // if the contact is really changed or a new one
    if ( (*mContact) != mgr->contact(mContact->localId()) || !isSavedContact )
    {
        int detailCount = mContact->details().count();
            
        // If its a new contact
        if ( !isSavedContact )
        {
            if ( detailCount > 2 )
            {
                bool success = mgr->saveContact( mContact );
                if ( success && mIsMyCard )
                {
                    mgr->setSelfContactId( mContact->localId() );
                }
                
                QString name = mgr->synthesizedDisplayLabel( *mContact );
                
                emit contactUpdated(success);
                
                if ( success )
                {
                    HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contact_1_saved")).arg(name));
                }
                else
                {
                    //TODO: localization is missing
                    HbDeviceNotificationDialog::notification(QString(),qtTrId("SAVING FAILED!"));
                }
                
                QVariant var;
                var.setValue(*mContact);
                mArgs.insert(ESelectedContact, var);
            }        
        }
        else
        {
            // contact details has been cleared out.
            if ( detailCount <= 4 )
            {
                // get the contact from database, it should have the name still in it,
                // and show the delete notification to user
                QContact c = mgr->contact( mContact->localId() );
                
                bool success = mgr->removeContact( mContact->localId() );
                emit contactRemoved(success);
            }
            else
            {
                bool success = mgr->saveContact(mContact);
                
                QString name = mgr->synthesizedDisplayLabel( *mContact );
                
                emit contactUpdated( success );
                
                if ( success )
                {
                    HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contacts_1_updated")).arg(name));
                }
                else
                {
                    //TODO: localization is missing
                    HbDeviceNotificationDialog::notification(QString(),qtTrId("SAVING FAILED!"));
                }
                
                QVariant var;
                var.setValue(*mContact);
                mArgs.insert(ESelectedContact, var);           
            }
        }
    }
    else
    {
        emit changesDiscarded();
    }
    
    mMgr->back( mArgs );
}

void CntEditViewPrivate::openNameEditor()
{
    QVariant var;
    var.setValue(*mContact);
            
    mArgs.insert(EViewId, namesEditorView);
    mArgs.insert(ESelectedAction, QString());
    mArgs.insert(ESelectedContact, var);
    
    mMgr->changeView( mArgs );
}

void CntEditViewPrivate::openImageEditor()
{
    QVariant var;
    var.setValue(*mContact);
                
    mArgs.insert(ESelectedContact, var);
    mArgs.insert(ESelectedAction, QString());
    mArgs.insert(EViewId, imageEditorView );
        
    mMgr->changeView( mArgs );
}

void CntEditViewPrivate::loadAvatar()
{
    QList<QContactAvatar> details = mContact->details<QContactAvatar>();
    for (int i = 0;i < details.count();i++)
    {
        QUrl url = details.at(i).imageUrl();
        if ( url.isValid() )
        {
            mThumbnailManager->getThumbnail( url.toString() );
            break;
        }
    }
}

void CntEditViewPrivate::setScrollPosition()
{
    if ( mArgs.contains(ESelectedDetail) )
    {
        QContactDetail d = mArgs.value( ESelectedDetail ).value<QContactDetail>();
        
        QModelIndex index = mModel->itemIndex( d );
        if ( index.isValid() )
        {
            mListView->scrollTo( index, HbListView::EnsureVisible );
        }
    }
}

void CntEditViewPrivate::thumbnailReady( const QPixmap& pixmap, void *data, int id, int error )
{
    Q_UNUSED(data);
    Q_UNUSED(id);
    if (!error)
    {
        QIcon qicon(pixmap);
        HbIcon icon(qicon);
        mHeading->setIcon(icon);
        
        mImageLabel->clear();
        mImageLabel->setIcon(icon);
    }
}

HbMenu* CntEditViewPrivate::createPopup( const QModelIndex aIndex, CntEditViewItem* aDetail )
{
    HbMenu* menu = new HbMenu();
    CntStringMapper* map = new CntStringMapper();
    QVariant cd = aDetail->data( ERoleContactDetail );
    QContactDetail detail = cd.value<QContactDetail>();
    
    QVariant data( aIndex.row() );
    
    if ( !mModel->isEmptyItem(aDetail) ) 
    {
        // add is supported only on these items:
        // QContactPhonenumber, QContactOnlineAccount, QContactEmail, QContactUrl and QContactNote
        QString def = detail.definitionName(); 
        if ( def == QContactPhoneNumber::DefinitionName   || 
             def == QContactOnlineAccount::DefinitionName ||
             def == QContactEmailAddress::DefinitionName  ||
             def == QContactUrl::DefinitionName || 
             def == QContactNote::DefinitionName )
        {
            HbAction* add = menu->addAction(map->getContactEditorAddLocString(detail.definitionName(), ""));
            add->setProperty( "menu", HbAction::NewRole );
            add->setData( data );
        }
        
        QString context;
        QString subtype;
        if ( def == QContactPhoneNumber::DefinitionName )
        {
            QContactPhoneNumber number(detail); 
            context = number.contexts().isEmpty() ? QString() : number.contexts().first();
            subtype = number.subTypes().isEmpty() ? number.definitionName() : number.subTypes().first();
        }
        else if ( def == QContactOnlineAccount::DefinitionName )
        {
            QContactOnlineAccount number(detail); 
            context = number.contexts().isEmpty() ? QString() : number.contexts().first();
            subtype = number.subTypes().isEmpty() ? number.definitionName() : number.subTypes().first();
        }
        else if ( def == QContactFamily::DefinitionName )
        {
            QStringList fields = aDetail->data(ERoleContactDetailFields).toStringList();
            subtype = fields.first();
        }
        else
        {
            context = QString();
            subtype = detail.definitionName();
        }
        
        HbAction* edit = menu->addAction(hbTrId("txt_common_menu_edit"));
        HbAction* del = menu->addAction(map->getContactEditorDelLocString(subtype, context));
        edit->setProperty( "menu", HbAction::EditRole );
        del->setProperty( "menu" , HbAction::DeleteRole );
        edit->setData( data );
        del->setData( data );
    }
    else
    {
        HbAction* add = menu->addAction(map->getContactEditorAddLocString(detail.definitionName(), ""));
        add->setProperty( "menu", HbAction::NewRole );
        add->setData( data );
    }
    delete map;
    return menu;
}

void CntEditViewPrivate::addDetail( CntEditViewItem* aDetail )
{
    QVariant id = aDetail->data( ERoleEditorViewId );
    CntViewParameters viewParameters;
    viewParameters.insert(EViewId, id.toInt());
    QVariant var;
    var.setValue(*mContact);
    viewParameters.insert(ESelectedContact, var);
    viewParameters.insert(ESelectedAction, "add" );
                                            
    mMgr->changeView( viewParameters );
}

void CntEditViewPrivate::editDetail( CntEditViewItem* aDetail )
{
    QVariant id = aDetail->data( ERoleEditorViewId );
    
    mArgs.insert(EViewId, id.toInt());
    mArgs.insert(ESelectedAction, QString() );
    QVariant var;
    var.setValue(*mContact);
    
    mArgs.insert(ESelectedContact, var);
                                              
    mMgr->changeView( mArgs );
}

void CntEditViewPrivate::removeDetail( CntEditViewItem* aDetail, const QModelIndex& aIndex )
{
    mModel->removeItem( aDetail, aIndex );
    mSave->setEnabled( true );
    mDiscard->setEnabled( true );
}

void CntEditViewPrivate::setSelectedContact( QContact aContact )
{
    if ( mContact )
    {
        delete mContact;
        mContact = NULL;
    }
    mContact = new QContact( aContact );
    
    if ( mModel )
    {
        delete mModel;
        mModel = NULL;
    }
    mModel = new CntEditViewListModel( mContact );
    
    if ( mListView )
        mListView->setModel( mModel );
}
// End of File