qtmobility/plugins/contacts/symbian/src/transform/cntthumbnailcreator.cpp
changeset 1 2b40d63a9c3d
child 11 06b8e2af4411
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/plugins/contacts/symbian/src/transform/cntthumbnailcreator.cpp	Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "cntthumbnailcreator.h"
+
+#include <cntdb.h> 
+#include <cntitem.h>
+
+#include <cntdef.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+#include <imageconversion.h>
+#include <gdi.h>
+#include <bitmaptransforms.h>
+#include <bautils.h>
+
+#if QT_VERSION < QT_VERSION_CHECK(4, 6, 0)
+#define QT_TRAP_THROWING QT_TRANSLATE_SYMBIAN_LEAVE_TO_EXCEPTION
+#define QT_TRYCATCH_LEAVING QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE
+#endif
+
+const TSize KThumbnailSizeUninitialized(0, 0);
+
+#ifdef _DEBUG
+_LIT(KPanicCategory, "ThumbnailCreator");
+enum TPanicReasons {
+    KPanicUnitialized = 0
+};
+#endif
+
+CntThumbnailCreator::CntThumbnailCreator() :
+    CActive(EPriorityStandard),
+    m_state(EStateInitialized),
+    m_thumbnailSize(KThumbnailSizeUninitialized),
+    m_thumbnailFieldFromTemplate(0),
+    m_err(KErrNone)
+{
+    CActiveScheduler::Add(this);
+}
+
+CntThumbnailCreator::~CntThumbnailCreator()
+{
+    delete m_encoder;
+    delete m_imageData;
+    delete m_bitmapScaler;
+    delete m_bitmap;
+    delete m_decoder;
+    delete m_activeSchedulerWait;
+    if (m_rfs.Handle() != KNullHandle)
+        m_rfs.Close();
+}
+
+/*!
+ * After calling this function \a fieldList will contain thumbnail field (field
+ * types KUidContactFieldVCardMapJPEG, KUidContactFieldPicture in this order)
+ * with thumbnail data. If the file \a filename does not exist, no fields are
+ * added to the field list. If the file \a filename is not a valid image file,
+ * a leave will occur. \a maxSize is the maximum size of the thumbnail image
+ * that is stored into contact database. If the image is bigger than \a maxSize
+ * the generated thumbnail will be scaled down to \a maxSize.
+ */
+void CntThumbnailCreator::addThumbnailFieldL(QList<CContactItemField *> *fieldList, const TFileName &filename, const TSize& maxSize)
+{
+    Cancel();
+    m_fieldList = fieldList;
+    m_thumbnailSize = maxSize;
+
+    // Lazy instantiation to save resources
+    if (m_rfs.Handle() == KNullHandle)
+        m_rfs.Connect();
+    if(!m_activeSchedulerWait)
+        m_activeSchedulerWait = new (ELeave) CActiveSchedulerWait;
+
+    DecodeImageL(filename);
+
+    // Synchronize asynchronous operations (wait loop is finished in RunL when
+    // image operations are done, or in RunError if an error occurs)
+    m_activeSchedulerWait->Start();
+    User::LeaveIfError(m_err);
+}
+
+void CntThumbnailCreator::addThumbnailFieldL(QList<CContactItemField *> *fieldList, CFbsBitmap *bitmap, const TSize& maxSize)
+{
+    Cancel();
+    m_fieldList = fieldList;
+    m_thumbnailSize = maxSize;
+    delete m_bitmap;
+    m_bitmap = bitmap;
+
+    // Lazy instantiation to save resources
+    if (m_rfs.Handle() == KNullHandle)
+        m_rfs.Connect();
+    if(!m_activeSchedulerWait)
+        m_activeSchedulerWait = new (ELeave) CActiveSchedulerWait;
+
+    m_state = EStateEncodeImage;
+    EncodeImageL();
+
+    // Synchronize asynchronous operations (wait loop is finished in RunL when
+    // image operations are done, or in RunError if an error occurs)
+    m_activeSchedulerWait->Start();
+    User::LeaveIfError(m_err);
+}
+
+
+void CntThumbnailCreator::RunL()
+{
+    __ASSERT_DEBUG(m_activeSchedulerWait, User::Panic(KPanicCategory, KPanicUnitialized));
+
+    User::LeaveIfError(iStatus.Int());
+    switch (m_state) {
+    case EStateDecodeImage:
+    {
+        m_state = EStateScaleImage;
+        ScaleImageL();
+        break;
+    }
+    case EStateScaleImage:
+    {
+        m_state = EStateEncodeImage;
+        EncodeImageL();
+        break;
+    }
+    case EStateEncodeImage:
+    {
+        m_state = EStateFinal;
+        CreateContactFieldL();
+        break;
+    }
+    case EStateFinal:
+    {
+        // We are done with the image, back to the caller of convertL
+        m_activeSchedulerWait->AsyncStop();
+        break;
+    }
+    default:
+        User::Leave(KErrCompletion);
+    }
+}
+
+void CntThumbnailCreator::DoCancel()
+{
+    __ASSERT_DEBUG(m_activeSchedulerWait, User::Panic(KPanicCategory, KPanicUnitialized));
+
+    m_err = KErrCancel;
+    m_activeSchedulerWait->AsyncStop();
+}
+
+TInt CntThumbnailCreator::RunError(TInt aError)
+{
+    __ASSERT_DEBUG(m_activeSchedulerWait, User::Panic(KPanicCategory, KPanicUnitialized));
+
+    m_err = aError;
+    m_activeSchedulerWait->AsyncStop();
+    return KErrNone;
+}
+
+void CntThumbnailCreator::DecodeImageL(const TFileName &filename)
+{
+    if (m_rfs.IsValidName(filename) && BaflUtils::FileExists(m_rfs, filename)) {
+        m_state = EStateDecodeImage;
+
+        // Create image decoder
+        delete m_decoder;
+        m_decoder = 0;
+        m_decoder = CImageDecoder::FileNewL(m_rfs, filename);
+        TFrameInfo frameInfo = m_decoder->FrameInfo();
+
+        // Lazy instantiation
+        if(!m_bitmap)
+            m_bitmap = new (ELeave) CFbsBitmap;
+        User::LeaveIfError(m_bitmap->Create(frameInfo.iOverallSizeInPixels, frameInfo.iFrameDisplayMode));
+
+        m_decoder->Convert(&iStatus, *m_bitmap);
+    } else {
+        m_state = EStateFinal;
+
+        // Ignore "file does not exist" error because the image has probably
+        // been removed (leaves thumbnail field empty for the contact).
+        TRequestStatus *status = &iStatus;
+        User::RequestComplete(status, KErrNone);
+    }
+    SetActive();
+}
+
+void CntThumbnailCreator::ScaleImageL()
+{
+    __ASSERT_DEBUG(m_decoder, User::Panic(KPanicCategory, KPanicUnitialized));
+    __ASSERT_DEBUG(m_thumbnailSize != KThumbnailSizeUninitialized, User::Panic(KPanicCategory, KPanicUnitialized));
+
+    TFrameInfo frameInfo = m_decoder->FrameInfo();
+
+    // Scale down if the image is too big
+    if ( frameInfo.iOverallSizeInPixels.iWidth > m_thumbnailSize.iWidth
+            || frameInfo.iOverallSizeInPixels.iHeight > m_thumbnailSize.iHeight) {
+        // Lazy instantiation
+        if(!m_bitmapScaler)
+            m_bitmapScaler = CBitmapScaler::NewL();
+        m_bitmapScaler->Scale(&iStatus, *m_bitmap, m_thumbnailSize);
+    } else {
+        // No need to scale, complete request immediately
+        TRequestStatus *status = &iStatus;
+        User::RequestComplete(status, KErrNone);
+    }
+    SetActive();
+}
+
+void CntThumbnailCreator::EncodeImageL()
+{
+    delete m_imageData;
+    m_imageData = 0;
+    delete m_encoder;
+    m_encoder = 0;
+    m_encoder = CImageEncoder::DataNewL(m_imageData, CImageEncoder::EOptionNone, KImageTypeJPGUid);
+    m_encoder->Convert(&iStatus, *m_bitmap);
+    SetActive();
+}
+
+void CntThumbnailCreator::CreateContactFieldL()
+{
+    __ASSERT_DEBUG(m_imageData, User::Panic(KPanicCategory, KPanicUnitialized));
+
+    initializeThumbnailFieldL();
+    CContactItemField *thumbnailField = CContactItemField::NewLC(*m_thumbnailFieldFromTemplate);
+
+    thumbnailField->StoreStorage()->SetThingL(*m_imageData);
+    QT_TRYCATCH_LEAVING(m_fieldList->append(thumbnailField));
+    CleanupStack::Pop(thumbnailField);
+
+    // Complete request to proceed to the final state
+    TRequestStatus *status = &iStatus;
+    User::RequestComplete(status, KErrNone);
+    SetActive();
+}
+
+void CntThumbnailCreator::initializeThumbnailFieldL()
+{
+    // Assume the golden template is not changed run-time and fetch it only
+    // when initializeThumbnailFieldL is called for the first time during the
+    // life-time of the CntThumbnailCreator object (requires the instance to
+    // live longer than one thumbnail create operation to be effective,
+    // otherwise we would end up opening contact database and reading the
+    // system template every time a thumbnail is stored for a contact).
+    if(!m_thumbnailFieldFromTemplate) {
+        CContactDatabase *contactDatabase = CContactDatabase::OpenL();
+        CleanupStack::PushL(contactDatabase);
+        CContactItem *goldenTemplate = contactDatabase->ReadContactLC(KGoldenTemplateId);
+        const CContactItemFieldSet& cardFields = goldenTemplate->CardFields();
+
+        // Check if thumbnail field type is KUidContactFieldPictureValue
+        TInt pictureFieldIndex = cardFields.Find(KUidContactFieldPicture, KUidContactFieldVCardMapPHOTO);
+
+        // Check if thumbnail field type is KUidContactFieldVCardMapJPEG
+        if(pictureFieldIndex == KErrNotFound) {
+            pictureFieldIndex = cardFields.Find(KUidContactFieldVCardMapJPEG, KUidContactFieldVCardMapPHOTO);
+        }
+
+        if(pictureFieldIndex == KErrNotFound) {
+            // Either KUidContactFieldPictureValue or KUidContactFieldVCardMapJPEG
+            // thumbnail field types should be in the template
+            User::Leave(KErrNotFound);
+        }
+
+        m_thumbnailFieldFromTemplate = CContactItemField::NewL(cardFields[pictureFieldIndex]);
+        CleanupStack::PopAndDestroy(goldenTemplate);
+        CleanupStack::PopAndDestroy(contactDatabase);
+    }
+}