diff -r d4f567ce2e7c -r 5b6f26637ad3 phonebookui/pbkcommonui/src/cnteditview_p.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookui/pbkcommonui/src/cnteditview_p.cpp Tue Aug 31 15:05:21 2010 +0300 @@ -0,0 +1,800 @@ +/* +* 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 "cntthumbnailmanager.h" +#include "cntimagelabel.h" +#include "cntsavemanager.h" +#include +#include "cntglobal.h" +#include "cntdebug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +const char *CNT_EDIT_XML = ":/xml/contacts_ev.docml"; + +CntEditViewPrivate::CntEditViewPrivate() : + mModel( NULL ), + mImageLabel( NULL ), + mThumbnailManager( NULL ), + mContact( NULL ), + mReq(NULL), + mMenu(NULL), + mSaveManager(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( mDocument->findWidget("view") ); + + mListView = static_cast( mDocument->findWidget("listView") ); + mListView->setLayoutName("editviewlist"); + mListView->setItemPixmapCacheEnabled(true); + + HbFrameBackground frame; + frame.setFrameGraphicsName("qtg_fr_list_normal"); + frame.setFrameType(HbFrameDrawer::NinePieces); + mListView->listItemPrototype()->setDefaultFrame( frame ); + + mHeading = static_cast( mDocument->findWidget("editViewHeading") ); + mImageLabel = static_cast(mDocument->findWidget("editViewImage")); + + mSoftkey = new HbAction(Hb::BackNaviAction, mView); + mDiscard = static_cast( mDocument->findObject("cnt:discard") ); + mDiscard->setParent(mView); + + mSave = static_cast( mDocument->findObject("cnt:savecontact") ); + mSave->setParent(mView); + + mDelete = static_cast( mDocument->findObject("cnt:deletecontact") ); + mDelete->setParent(mView); + + HbAction* add = static_cast( 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&)) ); + + // closing the application from task swapper or end key will cause the contact to be saved + connect( qApp, SIGNAL(aboutToQuit()), this, SLOT(saveChanges())); +} + +CntEditViewPrivate::~CntEditViewPrivate() +{ + mView->deleteLater(); + + delete mDocument; + mDocument = NULL; + delete mModel; + mModel = NULL; + delete mContact; + mContact = NULL; + if (mMenu) + { + delete mMenu; + mMenu = NULL; + } + + delete mSaveManager; + mSaveManager = NULL; +} + +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( const CntViewParameters aArgs ) +{ + CNT_ENTRY + + mArgs = aArgs; + mMgr = &mEngine->viewManager(); + + 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() ); + mModel = new CntEditViewListModel( *mContact, mEngine->extensionManager() ); + mListView->setModel( mModel ); + + QContactLocalId localId = mContact->localId(); + QContactManager& cm = mEngine->contactManager(SYMBIAN_BACKEND); + QContactLocalId selfContactId = cm.selfContactId(); + mIsMyCard = ( localId == selfContactId && localId != 0 ) || !myCard.isEmpty(); + + if (mIsMyCard) + { + mSaveManager = new CntSaveManager(CntSaveManager::EMyCard); + } + else + { + mSaveManager = new CntSaveManager(); + } + + 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( 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 = &mEngine->thumbnailManager(); + connect( mThumbnailManager, SIGNAL(thumbnailReady(QPixmap, void*, int, int)), + this, SLOT(thumbnailReady(QPixmap, void*, int, int)) ); + + loadAvatar(); + + CNT_EXIT +} + +void CntEditViewPrivate::deactivate() +{ +} + +void CntEditViewPrivate::openView(CntViewParameters& viewParams) +{ + QList 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 if( item->data(ERoleEditorViewId) == ringToneFetcherView ) + { + fetchTone(); + } + 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 + { + if (mMenu) + { + delete mMenu; + } + mMenu = createPopup( aItem->modelIndex(), item ); + mMenu->setPreferredPos( aCoords ); + mMenu->setModal( true ); + mMenu->open( this, SLOT(handleMenuAction(HbAction*)) ); + } +} + +void CntEditViewPrivate::handleMenuAction( HbAction* aAction ) +{ + HbMenu *menu = static_cast(sender()); + if ( aAction ) + { + int row = aAction->data().toInt(); + mIndex = mModel->index(row, 0); + CntEditViewItem* item = mModel->itemAt( mIndex ); + + switch ( aAction->property("menu").toInt() ) + { + case HbAction::EditRole: + { + if( item->data(ERoleEditorViewId) == ringToneFetcherView ) + { + fetchTone(); + menu->close(); + } + else + { + editDetail( item ); + } + } + break; + + case HbAction::NewRole: + { + addDetail( item ); + } + break; + + case HbAction::DeleteRole: + { + removeDetail( item, mIndex ); + } + 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(sender()); + + if (popup && aAction != popup->actions().first() && popup->selectedItems().count()) + { + int row = popup->selectedItems().first().toInt(); + QModelIndex index = popup->model()->index(row, 0); + int id = popup->model()->data(index, Qt::UserRole).toInt(); + + if (id != noView ) + { + mArgs.insert(EViewId, id ); + + switch ( id ) + { + case phoneNumberEditorView: + case emailEditorView: + case urlEditorView: + case noteEditorView: + mArgs.insert( ESelectedAction, CNT_ADD_ACTION ); + changeEditorView(); + break; + case addressEditorView: + case dateEditorView: + case companyEditorView: + case familyDetailEditorView: + mArgs.insert( ESelectedAction, CNT_FOCUS_ACTION ); + changeEditorView(); + break; + case ringToneFetcherView: + fetchTone(); + break; + default: + break; + } + } + } +} + +void CntEditViewPrivate::changeEditorView() +{ + QVariant var; + var.setValue(*mContact); + mArgs.insert(ESelectedContact, var); + mMgr->changeView( mArgs ); +} + +// Call IToneFetch Service +void CntEditViewPrivate::fetchTone() +{ + if(mReq) + { + delete mReq; + mReq = 0; + } + //launch media fetcher + mReq = mAppMgr.create(XQI_TONE_FETCH, XQOP_TONE_FETCH, true); // read strings from header file constants + if (!mReq) + { + return; + } + else + { + connect(mReq, SIGNAL( requestOk( const QVariant&)), SLOT( ringToneFetchHandleOk(const QVariant&)) ); + connect(mReq, SIGNAL( requestError( int,const QString&)), SLOT(ringToneFetchHandleError(int,const QString&)) ); + } + + // Make the request + mReq->send(); +} + +void CntEditViewPrivate::ringToneFetchHandleOk(const QVariant &result) +{ + + QContactRingtone ringtone = mContact->detail(); + QUrl ringtoneUrl = ringtone.audioRingtoneUrl(); + QFileInfo ringtoneFileInfo(ringtoneUrl.toString()); + QString ringtoneFileName = ringtoneFileInfo.fileName(); + // Contact can have only one ringtone at a time + // remove existing ringtone detail if any + + if(!(ringtone.isEmpty())) + { + mContact->removeDetail(&ringtone); + } + + ringtone.setAudioRingtoneUrl(result.value()); + mContact->saveDetail( &ringtone ); + mModel->updateRingtone(); + mSave->setEnabled( true ); + mDiscard->setEnabled( true ); + +} + +void CntEditViewPrivate::ringToneFetchHandleError(int errorCode, const QString& errorMessage) +{ + Q_UNUSED(errorCode); + Q_UNUSED(errorMessage); + +} + + +void CntEditViewPrivate::deleteContact() +{ + CNT_ENTRY + + if ( mIsMyCard ) + { + HbMessageBox::question(hbTrId("txt_phob_dialog_remove_all_personal_data_from_my_c"), this, + SLOT(handleDeleteContact(int)), + HbMessageBox::Yes | HbMessageBox::No); + } + else + { + QContactManager& cm = mEngine->contactManager( SYMBIAN_BACKEND ); + QString name = cm.synthesizedContactDisplayLabel( *mContact ); + if (name.isEmpty()) + { + name = hbTrId("txt_phob_list_unnamed"); + } + + HbMessageBox::question(HbParameterLengthLimiter(hbTrId("txt_phob_info_delete_1")).arg(name), this, SLOT(handleDeleteContact(int)), + HbMessageBox::Delete | HbMessageBox::Cancel); + } + + CNT_EXIT +} + +void CntEditViewPrivate::handleDeleteContact(int action) +{ + CNT_ENTRY + + Q_Q(CntEditView); + + if(action == HbMessageBox::Yes || action == HbMessageBox::Delete) + { + QContactManager& cm = mEngine->contactManager( SYMBIAN_BACKEND ); + + disconnect(&cm, SIGNAL(contactsRemoved(const QList&)), + this, SLOT(contactDeletedFromOtherSource(const QList&))); + emit q->contactRemoved(cm.removeContact( mContact->localId() )); + + mMgr->back( mArgs, true ); + } + + CNT_EXIT +} + +void CntEditViewPrivate::discardChanges() +{ + Q_Q(CntEditView); + + emit q->changesDiscarded(); + + // get a fresh one from backend. + QContactManager& mgr = mEngine->contactManager(SYMBIAN_BACKEND); + setSelectedContact( mgr.contact( mContact->localId()) ); + + QVariant var; + var.setValue(*mContact); + + mArgs.insert(ESelectedContact, var); + + if ( mArgs.value( EExtraAction ).toString() == CNT_ROOT_ACTION ) + { + mMgr->back( mArgs, true ); + } + else + { + mMgr->back( mArgs ); + } + +} + +void CntEditViewPrivate::saveChanges() +{ + CNT_ENTRY + + Q_Q(CntEditView); + + QContactManager& mgr = mEngine->contactManager(SYMBIAN_BACKEND); + QString name = mgr.synthesizedContactDisplayLabel(*mContact); + + if (name.isEmpty()) + { + name = hbTrId("txt_phob_list_unnamed"); + } + + disconnect(&mgr, SIGNAL(contactsRemoved(const QList&)), + this, SLOT(contactDeletedFromOtherSource(const QList&))); + CntSaveManager::CntSaveResult result = mSaveManager->saveContact(mContact, &mgr); + + QVariant var; + bool backToRoot(false); + + switch (result) + { + case CntSaveManager::ESaved: + emit q->contactUpdated(KCntServicesReturnValueContactSaved); + HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contact_1_saved")).arg(name)); + var.setValue(*mContact); + mArgs.insert(ESelectedContact, var); + mArgs.insert(ESelectedAction, CNT_CREATE_ACTION); + break; + case CntSaveManager::EUpdated: + emit q->contactUpdated(KCntServicesReturnValueContactSaved); + HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contacts_1_updated")).arg(name)); + var.setValue(*mContact); + mArgs.insert(ESelectedContact, var); + mArgs.insert(ESelectedAction, CNT_EDIT_ACTION); + break; + case CntSaveManager::EFailed: + emit q->contactUpdated(KCntServicesReturnValueContactNotModified); + HbDeviceNotificationDialog::notification(QString(),hbTrId("SAVING FAILED!")); + break; + case CntSaveManager::EDeleted: + emit q->contactRemoved(true); + backToRoot = true; + break; + case CntSaveManager::ENothingDone: + default: + emit q->contactUpdated(KCntServicesReturnValueContactNotModified); + break; + } + + if ( mArgs.value( EExtraAction ).toString() == CNT_ROOT_ACTION ) + { + backToRoot = true; + } + + mMgr->back( mArgs, backToRoot ); + + CNT_EXIT +} + +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 details = mContact->details(); + for (int i = 0;i < details.count();i++) + { + QUrl url = details.at(i).imageUrl(); + if ( url.isValid() ) + { + mThumbnailManager->getThumbnail( ThumbnailManager::ThumbnailLarge, url.toString() ); + break; + } + } +} + +void CntEditViewPrivate::setScrollPosition() +{ + if ( mArgs.contains(ESelectedDetail) ) + { + QContactDetail d = mArgs.value( ESelectedDetail ).value(); + + 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) + { + HbIcon icon(pixmap); + mHeading->setIcon(icon); + + mImageLabel->clear(); + mImageLabel->setIcon(pixmap); + } +} + +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(); + + 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 ); + + mArgs.insert(EViewId, id.toInt()); + mArgs.insert(ESelectedAction, CNT_ADD_ACTION ); + QVariant var; + var.setValue(*mContact); + + mArgs.insert(ESelectedContact, var); + + mMgr->changeView( mArgs ); +} + +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 ) +{ + CNT_ENTRY + + if ( mContact ) + { + delete mContact; + mContact = NULL; + } + mContact = new QContact( aContact ); + + QContactManager& cm = mEngine->contactManager( SYMBIAN_BACKEND ); + connect(&cm, SIGNAL(contactsRemoved(const QList&)), + this, SLOT(contactDeletedFromOtherSource(const QList&)), Qt::UniqueConnection); + CNT_EXIT +} + +void CntEditViewPrivate::contactDeletedFromOtherSource(const QList& contactIds) +{ + CNT_ENTRY + + if ( contactIds.contains(mContact->localId()) ) + { + // Do not switch to the previous view immediately. List views are + // not updated properly if this is not done in the event loop + QTimer::singleShot(0, this, SLOT(showRootView())); + } + + CNT_EXIT +} + +void CntEditViewPrivate::showRootView() +{ + CNT_ENTRY + + Q_Q(CntEditView); + + emit q->contactRemoved(true); + mMgr->back( mArgs, true ); + + CNT_EXIT +} + +// End of File +