phonebookui/pbkcommonui/src/cntimageeditorview.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 09:39:00 +0300
changeset 59 a642906a277a
parent 47 7cbcb2896f0e
child 65 ae724a111993
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:
*
*/

#include "cntimageeditorview.h"
#include "cntimageutility.h"
#include "cntsavemanager.h"
#include "cntimagelabel.h"

#include <hblabel.h>
#include <xqaiwrequest.h>
#include <xqaiwdecl.h>

#include "cntdebug.h"
#include "cntglobal.h"

#include <thumbnailmanager_qt.h>
#include <hbaction.h>
#include <hbview.h>
#include <hbmainwindow.h>
#include <hblistview.h>
#include <hblistviewitem.h>
#include <hbframebackground.h>
#include <hbdevicenotificationdialog.h>
#include <hbparameterlengthlimiter.h>

#include <QStandardItemModel>
#include <QApplication>

const char *CNT_IMAGE_XML = ":/xml/contacts_if.docml";

/*!
Constructor
*/
CntImageEditorView::CntImageEditorView() :
    mContact(NULL),
    mAvatar(NULL),
    mImageLabel(NULL),
    mRequest(NULL),
    mViewManager(NULL),
    mListView(NULL),
    mModel(NULL),
    mSaveManager(NULL)
{
    bool ok = false;
    mDocumentLoader.load(CNT_IMAGE_XML, &ok);

    if (ok)
    {
        mView = static_cast<HbView*>(mDocumentLoader.findWidget(QString("view")));
    }
    else
    {
        qFatal("Unable to read :/xml/contacts_if.docml");
    }
    
    //back button
    mSoftkey = new HbAction(Hb::BackNaviAction, mView);
    connect(mSoftkey, SIGNAL(triggered()), this, SLOT(showPreviousView()));
    
    // menu action
    mRemoveImage = static_cast<HbAction*>(mDocumentLoader.findObject("cnt:removeimage"));
    connect(mRemoveImage, SIGNAL(triggered()), this, SLOT(removeImage()));

    // thumbnail manager
    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)) );
    
    // closing the application from task swapper or end key will cause the contact to be saved
    connect( qApp, SIGNAL(aboutToQuit()), this, SLOT(saveContact()));
}

/*!
Destructor
*/
CntImageEditorView::~CntImageEditorView()
{
    CNT_ENTRY
    
    mView->deleteLater();

    delete mAvatar;
    mAvatar = NULL;
    delete mContact;
    mContact = NULL;
    delete mRequest;
    mRequest = NULL;
    delete mRemoveImage;
    mRemoveImage = NULL;
    delete mModel;
    mModel = NULL;
    delete mSaveManager;
    mSaveManager = NULL;
    
    CNT_EXIT
}

/*!
Called when activating the view
*/
void CntImageEditorView::activate( CntAbstractViewManager* aMgr, const CntViewParameters aArgs )
{
    mViewManager = aMgr;
    mArgs = aArgs;
    
    if (mView->navigationAction() != mSoftkey)
        mView->setNavigationAction(mSoftkey);
    
    HbMainWindow* window = mView->mainWindow();
    if ( window )
    {
        connect(window, SIGNAL(orientationChanged(Qt::Orientation)), this, SLOT(setOrientation(Qt::Orientation)));
        setOrientation(window->orientation());
    }
    
    if ( mArgs.contains(ESelectedContact))
    {
        mContact = new QContact(mArgs.value(ESelectedContact).value<QContact>());
    }
    
    if ( mArgs.contains(ESelectedGroupContact) && !mContact ) 
    {
        mContact = new QContact(mArgs.value(ESelectedGroupContact).value<QContact>());
    }
    
    QString myCard = mArgs.value( EMyCard ).toString();
    QContactLocalId localId = mContact->localId();
    QContactLocalId selfContactId = mViewManager->contactManager(SYMBIAN_BACKEND)->selfContactId();
    bool isMyCard = ( localId == selfContactId && localId != 0 ) || !myCard.isEmpty();
    
    if (isMyCard)
    {
        mSaveManager = new CntSaveManager(CntSaveManager::EMyCard);
    }
    else if (mContact->type() == QContactType::TypeGroup)
    {
        mSaveManager = new CntSaveManager(CntSaveManager::EGroup);
    }
    else
    {
        mSaveManager = new CntSaveManager();
    }
    
    // set the correct image if the contact already has an image set
    mImageLabel = static_cast<CntImageLabel*>(mDocumentLoader.findWidget(QString("cnt_image_label")));
    mImageLabel->ungrabGesture(Qt::TapGesture);
    QList<QContactAvatar> details = mContact->details<QContactAvatar>();
    if (details.count() > 0)
        {
        for (int i = 0;i < details.count();i++)
            {
                if (details.at(i).imageUrl().isValid())
                    {
                    mAvatar = new QContactAvatar(details.at(i));
                    mThumbnailManager->getThumbnail(mAvatar->imageUrl().toString());
                    break;
                    }
            }
        }
    else
        {
        mAvatar = new QContactAvatar();
        mRemoveImage->setEnabled(false);
        if (mContact->type() == QContactType::TypeGroup)
            {
            mImageLabel->setAvatarIcon(HbIcon("qtg_large_add_group_picture"));
            }
        }
    
    // set up the list
    mListView = static_cast<HbListView*>(mDocumentLoader.findWidget(QString("cnt_listview")));
    
    connect(mListView, SIGNAL(activated(const QModelIndex&)), this,
        SLOT(listViewActivated(const QModelIndex&)));
    
    HbFrameBackground frame;
    frame.setFrameGraphicsName("qtg_fr_list_normal");
    frame.setFrameType(HbFrameDrawer::NinePieces);
    mListView->itemPrototypes().first()->setDefaultFrame(frame);
    
    mListView->listItemPrototype()->setGraphicsSize(HbListViewItem::LargeIcon);
    mListView->setUniformItemSizes(true);
    
    mModel = new QStandardItemModel();
    populateModel(mModel);
    mListView->setModel(mModel);
}

void CntImageEditorView::deactivate()
{

}

void CntImageEditorView::populateModel(QStandardItemModel *model)
{
    QStandardItem *newPhoto = new QStandardItem();
    newPhoto->setText(hbTrId("txt_phob_list_take_a_new_photo"));
    newPhoto->setData(HbIcon("qtg_large_camera"), Qt::DecorationRole);
    model->appendRow(newPhoto);
    
    QStandardItem *fromGallery = new QStandardItem();
    fromGallery->setText(hbTrId("txt_phob_list_chooce_from_gallery"));
    fromGallery->setData(HbIcon("qtg_large_photos"), Qt::DecorationRole);
    model->appendRow(fromGallery);
}

/*!
Open camera and get new image for contact
*/
void CntImageEditorView::openCamera()
{
    CNT_ENTRY
    
    if (mRequest)
    {
        delete mRequest;
        mRequest = 0;
    }
    
    mRequest = mAppManager.create(XQI_CAMERA_CAPTURE, XQOP_CAMERA_CAPTURE, false);
    if ( mRequest ) 
    {
        int mode = 0; //image mode
        
        QVariantMap map;
        map.insert(XQCAMERA_INDEX, 0);
        map.insert(XQCAMERA_QUALITY, 0);
        map.insert(XQCAMERA_MODE_SWITCH, false);
        map.insert(XQCAMERA_INDEX_SWITCH, false);
        map.insert(XQCAMERA_QUALITY_CHANGE, true);
        
        // Set function parameters
        QList<QVariant> args;
        args << mode;
        args << map;
        mRequest->setArguments(args);
        
        connect(mRequest, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleImageChange(const QVariant&)));
        connect(mRequest, SIGNAL(requestError(int,const QString&)), this, SLOT(handleError(int,const QString&)));

        mRequest->send();
    }
    
    CNT_EXIT
}

/*!
Open gallery and select image for contact
*/
void CntImageEditorView::openGallery()
{
    if (mRequest)
    {
        delete mRequest;
        mRequest = 0;
    }
    
    mRequest = mAppManager.create(XQI_IMAGE_FETCH, XQOP_IMAGE_FETCH, true);
    if ( mRequest ) 
    {
        connect(mRequest, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleImageChange(const QVariant&)));
        mRequest->send();
    }
}

/*!
Called when user closes the view
*/
void CntImageEditorView::showPreviousView()
{
    mContact->saveDetail(mAvatar);

    if ( mAvatar->imageUrl().isEmpty())
    {
        mContact->removeDetail(mAvatar);
    }
    
    QVariant var;
    var.setValue(*mContact);
    
    // If the arguments didn't originally contain "normal" contact,
    // then the group contact should be updated. This case applies only
    // when group image is edited
    if ( !mArgs.contains(ESelectedContact) )
    {
        mArgs.insert(ESelectedGroupContact, var);
    }
    else
    {
        mArgs.insert(ESelectedContact, var);
    }
    
    mArgs.insert(ECustomParam, viewId());
    mViewManager->back( mArgs );
}

void CntImageEditorView::removeImage()
{
    QString filePath=mAvatar->imageUrl().toString();
    if(!filePath.isEmpty())
    {
        // Check if image removable.
        CntImageUtility imageUtility;
        if(imageUtility.isImageRemovable(filePath))
        {
            imageUtility.removeImage(filePath);
        }
        
        mAvatar->setImageUrl(QUrl());
        mImageLabel->clear();
        if (mContact->type() == QContactType::TypeGroup)
            mImageLabel->setAvatarIcon(HbIcon("qtg_large_add_group_picture"));
        else
            mImageLabel->setAvatarIcon(HbIcon("qtg_large_add_contact_picture"));
        mRemoveImage->setEnabled(false);
    }
}

/*!
Set the selected image as new QContactAvatar::SubTypeImage
*/
void CntImageEditorView::handleImageChange(const QVariant &value)
{
    CNT_ENTRY_ARGS("image path = " << value.toString())
    
    if(value.canConvert<QString>())
    {
        CntImageUtility imageUtility;
        if(imageUtility.isMassStorageAvailable())
        {
            CNT_LOG_ARGS("mass storage available")
            /* Copy image and create thumbnail
             * When contact image removed only copy is deleted
             */
            QString imagepath;
            if(imageUtility.createImage(value.toString(),imagepath))
            {
                
                // If image already assigned, delete
                QString filePath=mAvatar->imageUrl().toString();
                if(!filePath.isEmpty()
                   && imageUtility.isImageRemovable(filePath))
                    imageUtility.removeImage(filePath);
            
                CNT_LOG_ARGS("image created, image = " << filePath)
                
                mAvatar->setImageUrl(QUrl(imagepath));
                mThumbnailManager->getThumbnail(imagepath);
                mRemoveImage->setEnabled(true);
            }
        }
        else
        {
            // No mass memory, use the orginal image
            mAvatar->setImageUrl(QUrl(value.toString()));
            mThumbnailManager->getThumbnail(value.toString());
            mRemoveImage->setEnabled(true);
        }
    }
    
    CNT_EXIT
}

void CntImageEditorView::thumbnailReady(const QPixmap& pixmap, void *data, int id, int error)
{
    CNT_ENTRY_ARGS("error code = " << error)
    
    Q_UNUSED(data);
    Q_UNUSED(id);
    if (!error)
    {
        mImageLabel->clear();
        mImageLabel->setIcon(pixmap);
    }
    
    CNT_EXIT
}

void CntImageEditorView::setOrientation(Qt::Orientation orientation)
{
    if (orientation == Qt::Vertical) 
    {
        // reading "portrait" section
        mDocumentLoader.load(CNT_IMAGE_XML, "portrait");
    } 
    else 
    {
        // reading "landscape" section
        mDocumentLoader.load(CNT_IMAGE_XML, "landscape");
    }
}

/*!
Figure out which item was selected according to row number
*/
void CntImageEditorView::listViewActivated(const QModelIndex &index)
{
    if (index.isValid())
    {
        int row = index.row();
        switch(row)
        {
        case 0: // first item is always "take photo"
            openCamera();
            break;
        case 1: // and the second one is always "choose from gallery"
            openGallery();
            break;
        default:
            break;
        }
    }
}

void CntImageEditorView::handleError(int errorCode, const QString& errorMessage)
{
    Q_UNUSED(errorCode);
    Q_UNUSED(errorMessage);
    CNT_LOG_ARGS("error code = " << errorCode << "errorMessage=" << errorMessage)
}

void CntImageEditorView::saveContact()
{
    mContact->saveDetail(mAvatar);

    if ( mAvatar->imageUrl().isEmpty())
    {
        mContact->removeDetail(mAvatar);
    }
    
    QString name = mViewManager->contactManager(SYMBIAN_BACKEND)->synthesizedContactDisplayLabel(*mContact);
    
    if (name.isEmpty())
    {
        name = hbTrId("txt_phob_list_unnamed");
    }
    
    CntSaveManager::CntSaveResult result = mSaveManager->saveContact(mContact, mViewManager->contactManager(SYMBIAN_BACKEND));
    
    if (mContact->type() != QContactType::TypeGroup)
    {
        switch (result)
        {
        case CntSaveManager::ESaved:
            HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contact_1_saved")).arg(name));
            break;
        case CntSaveManager::EUpdated:
            HbDeviceNotificationDialog::notification(QString(),HbParameterLengthLimiter(hbTrId("txt_phob_dpophead_contacts_1_updated")).arg(name));
            break;
        case CntSaveManager::EFailed:
            HbDeviceNotificationDialog::notification(QString(),hbTrId("SAVING FAILED!"));
            break;
        case CntSaveManager::EDeleted:
        case CntSaveManager::ENothingDone:
        default:
            break;
        }
    }
}