diff -r fa1df4b99609 -r ebe688cedc25 messagingapp/msgui/appengine/src/conversationsmodel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingapp/msgui/appengine/src/conversationsmodel.cpp Tue Aug 31 15:11:31 2010 +0300 @@ -0,0 +1,1076 @@ +/* + * 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 "conversationsmodel.h" +#include "conversationsenginedefines.h" +#include "conversationmsgstorehandler.h" +#include "convergedmessage.h" +#include +#include "conversationsengineutility.h" +#include "unidatamodelloader.h" +#include "unidatamodelplugininterface.h" +#include "ringbc.h" +#include "msgcontacthandler.h" +#include "mmsconformancecheck.h" +#include +#include + +#include "debugtraces.h" + +#include +#include +#include +#include +#include +#include + +//CONSTANTS +_LIT(KDbFileName, "c:[2002A542]conversations.db"); + +// preview sql query +_LIT(KSelectConvMsgsStmt, "SELECT message_id, msg_processingstate, subject, body_text, preview_path, msg_property, preview_icon FROM conversation_messages WHERE message_id=:message_id "); + +//selecet preview-icon query +_LIT(KSelectPreviewIconStmt,"SELECT message_id, preview_icon FROM conversation_messages WHERE message_id = :message_id "); + +//selecet vcard-path query +_LIT(KSelectVCardStmt,"SELECT message_id, msg_processingstate, preview_path FROM conversation_messages WHERE message_id = :message_id "); + +// preview-cache max cost (items) +const int CACHE_COST = 50; +//Preview thumbnail size +const int KWidth = 9.5 * 6.7; +const int KHeight = 9.5 * 6.7; +//--------------------------------------------------------------- +// ConversationsModel::ConversationsModel +// Constructor +//--------------------------------------------------------------- +ConversationsModel::ConversationsModel(ConversationMsgStoreHandler* msgStoreHandler, + QObject* parent) : + QStandardItemModel(parent), mMsgStoreHandler(msgStoreHandler), iSqlDbOpen(EFalse) +{ + //Open SQL DB + if (KErrNone == iSqlDb.Open(KDbFileName)) + { + iSqlDbOpen = ETrue; + } + previewIconCache.setMaxCost(CACHE_COST); + + int err = connect(this, SIGNAL(retrievePreviewIcon(int, QString&)), this, + SLOT(updatePreviewIcon(int, QString&))); + QCRITICAL_WRITE_FORMAT("Error from connect()", err) + iDataModelPluginLoader = new UniDataModelLoader; + iMmsDataPlugin = iDataModelPluginLoader->getDataModelPlugin(ConvergedMessage::Mms); + iBioMsgPlugin = iDataModelPluginLoader->getDataModelPlugin(ConvergedMessage::BioMsg); +} + +//--------------------------------------------------------------- +// ConversationsModel::~ConversationsModel +// Destructor +//--------------------------------------------------------------- +ConversationsModel::~ConversationsModel() +{ + //Close SQL-DB + iSqlDb.Close(); + + //clear preview-cache + previewIconCache.clear(); + + if (iDataModelPluginLoader) { + delete iDataModelPluginLoader; + iDataModelPluginLoader = NULL; + } +} + +//--------------------------------------------------------------- +// ConversationsModel::data +// @see header +//--------------------------------------------------------------- +QVariant ConversationsModel::data(const QModelIndex & index, int role) const +{ + QVariant value; + QStandardItem* item = itemFromIndex(index); + switch (role) { + case ConversationId: + { + value = item->data(ConversationId); + break; + } + case UnReadStatus: + { + value = item->data(UnReadStatus); + break; + } + case ContactId: + { + value = item->data(ContactId); + break; + } + case TimeStamp: + { + value = item->data(TimeStamp); + break; + } + case ConvergedMsgId: + { + value = item->data(ConvergedMsgId); + break; + } + case MessageProperty: + { + value = item->data(MessageProperty); + break; + } + case MessageType: + { + value = item->data(MessageType); + break; + } + case MessageSubType: + { + value = item->data(MessageSubType); + break; + } + case Subject: + { + value = item->data(Subject); + break; + } + case BodyText: + { + value = item->data(BodyText); + break; + } + case ConversationAddress: + { + value = item->data(ConversationAddress); + break; + } + case Direction: + { + value = item->data(Direction); + break; + } + case SendingState: + { + value = item->data(SendingState); + break; + } + case PreviewIcon: + { + QString filepath(item->data(Attachments).toString()); + int msgId = item->data(ConvergedMsgId).toInt(); + HbIcon *icon = getPreviewIconItem(msgId, filepath); + return *icon; + } + case MessagePriority: + { + value = item->data(MessagePriority); + break; + } + case Attachments: + { + value = item->data(Attachments); + break; + } + case MessageLocation: + { + value = item->data(MessageLocation); + break; + } + case MessageStore: + { + value = item->data(MessageStore); + break; + } + case ConversationAlias: + { + value = item->data(ConversationAlias); + break; + } + case UnreadCount: + { + value = item->data(UnreadCount); + break; + } + case DisplayName: // Fall through start + value = item->data(DisplayName); + break; + case Avatar: // Fall througn end + value = item->data(Avatar); + break; + case NotificationStatus: + value = item->data(NotificationStatus); + break; + default: + { + //No matching role found, set invalid variant + value = QVariant(); + break; + } + } + return value; +} + +//--------------------------------------------------------------- +// ConversationsModel::addRow +// @see header +//--------------------------------------------------------------- +void ConversationsModel::addRow(const CCsConversationEntry& entry, bool dynamicUpdate) +{ + int msgId = entry.EntryId(); + //match, if found update else add item + QModelIndexList indexList = this->match(index(0, 0), ConvergedMsgId, msgId, -1, + Qt::MatchExactly); + + // if not found, add new item + if (indexList.count() == 0) { + QStandardItem* item = new QStandardItem(); + populateItem(*item, entry); + if (!dynamicUpdate) { + insertRow(0, item); + } + else { + int i; + for (i = rowCount() - 1; i >= 0; --i) { + QStandardItem* modelItem = this->item(i, 0); + if (modelItem->data(ConvergedMsgId).toInt() < item->data(ConvergedMsgId).toInt()) { + if (i == rowCount() - 1) { + appendRow(item); + } + else { + insertRow(i + 1, item); + } + return; + } + } + if (i == 0) { + insertRow(0, item); + } + } + } + else { + // Update an existing item + QModelIndex index = indexList[0]; + QStandardItem* item = this->item(index.row(), 0); + populateItem(*item, entry); + } +} + +//--------------------------------------------------------------- +// ConversationsModel::deleteRow +// @see header +//--------------------------------------------------------------- +void ConversationsModel::deleteRow(int msgId) +{ + //match, if found remove item + QModelIndexList indexList = + this->match(index(0, 0), ConvergedMsgId, msgId, 1, Qt::MatchExactly); + + if (indexList.count() == 1) { + QModelIndex index = indexList[0]; + this->removeRow(index.row()); + } +} + +//--------------------------------------------------------------- +// ConversationsModel::populateItem +// @see header +//--------------------------------------------------------------- +void ConversationsModel::populateItem(QStandardItem& item, const CCsConversationEntry& entry) +{ + QCRITICAL_WRITE("ConversationsModel::populateItem start."); + + int msgId = entry.EntryId(); + // id + item.setData(msgId, ConvergedMsgId); + + // description + HBufC* description = entry.Description(); + QString subject(""); + if (description && description->Length()) { + subject = (XQConversions::s60DescToQString(*description)); + } + + // time stamp + TTime unixEpoch(KUnixEpoch); + TTimeIntervalSeconds seconds; + TTime timeStamp(entry.TimeStamp()); + timeStamp.SecondsFrom(unixEpoch, seconds); + item.setData(seconds.Int(), TimeStamp); + + //contact details + HBufC* contact = entry.Contact(); + if (contact && contact->Length()) { + item.setData(XQConversions::s60DescToQString(*contact), ConversationAddress); + } + + // message type. + int msgType = ConversationsEngineUtility::messageType(entry.GetType()); + item.setData(msgType, MessageType); + + //message sub-type + item.setData(ConversationsEngineUtility::messageSubType(entry.GetType()), MessageSubType); + + // unread status + if (entry.IsAttributeSet(ECsAttributeUnread)) { + item.setData(true, UnReadStatus); + } + else { + item.setData(false, UnReadStatus); + } + + //sending state + item.setData(entry.GetSendState(), SendingState); + // direction + item.setData(entry.ConversationDir(), Direction); + + //location + if (entry.ConversationDir() == ECsDirectionIncoming) { + item.setData(ConvergedMessage::Inbox, MessageLocation); + } + else if (entry.IsAttributeSet(ECsAttributeDraft)) { + item.setData(ConvergedMessage::Draft, MessageLocation); + } + else if (entry.IsAttributeSet(ECsAttributeSent)) { + item.setData(ConvergedMessage::Sent, MessageLocation); + } + else { + item.setData(ConvergedMessage::Outbox, MessageLocation); + } + + //message specific handling + if (msgType == ConvergedMessage::Mms) { + QCRITICAL_WRITE("ConversationsModel::populateItem MMS start.") + handleMMS(item, entry); + QCRITICAL_WRITE("ConversationsModel::populateItem MMS end.") + } + else if(msgType == ConvergedMessage::MmsNotification) { + item.setData(subject, Subject); + handleMMSNotification(item, entry); + } + else if (msgType == ConvergedMessage::BT) { + handleBlueToothMessages(item, entry); + } + else if (msgType == ConvergedMessage::BioMsg) { + handleBioMessages(item, entry); + } + else { + // sms bodytext + item.setData(subject, BodyText); + } + + QCRITICAL_WRITE("ConversationsModel::populateItem end."); +} + +//--------------------------------------------------------------- +// ConversationsModel::validateMsgForForward +// @see header file +//--------------------------------------------------------------- +bool ConversationsModel::validateMsgForForward(qint32 messageId) +{ + bool retValue = true; + //Validate if the mms msg can be forwarded or not + MmsConformanceCheck* mmsConformanceCheck = new MmsConformanceCheck; + retValue = mmsConformanceCheck->validateMsgForForward(messageId); + + delete mmsConformanceCheck; + return retValue; +} + + +//--------------------------------------------------------------- +// ConversationsModel::handleMMS +// @see header +//--------------------------------------------------------------- +void ConversationsModel::handleMMS(QStandardItem& item, const CCsConversationEntry& entry) +{ + //msg_id + int msgId = entry.EntryId(); + + bool isEntryInDb = false; + TInt err = KErrNone; + + //check if db is open and query db + if (iSqlDbOpen) + { + RSqlStatement sqlSelectStmt; + err = sqlSelectStmt.Prepare(iSqlDb, KSelectConvMsgsStmt); + + // move to fallback option + if (KErrNone == err) + { + TInt msgIdIndex = sqlSelectStmt.ParameterIndex(_L(":message_id")); + TInt msgProcessingStateIndex = sqlSelectStmt.ColumnIndex(_L("msg_processingstate")); + TInt subjectIndex = sqlSelectStmt.ColumnIndex(_L("subject")); + TInt bodyIndex = sqlSelectStmt.ColumnIndex(_L("body_text")); + TInt previewPathIndex = sqlSelectStmt.ColumnIndex( + _L("preview_path")); + TInt msgpropertyIndex = sqlSelectStmt.ColumnIndex( + _L("msg_property")); + TInt previewIconIndex = sqlSelectStmt.ColumnIndex( + _L("preview_icon")); + + err = sqlSelectStmt.BindInt(msgIdIndex, msgId); + + // populate item + if ((KErrNone == err) && (sqlSelectStmt.Next() == KSqlAtRow)) + { + int msgProcessingState = 0; + msgProcessingState = sqlSelectStmt.ColumnInt( + msgProcessingStateIndex); + if (msgProcessingState == EPreviewMsgProcessed) + { + // use entry to populate model only when, + // entry is present in DB and its processing is over. + RBuf subjectBuffer; + if( subjectBuffer.Create( + sqlSelectStmt.ColumnSize( + subjectIndex)) == KErrNone) + { + sqlSelectStmt.ColumnText(subjectIndex, subjectBuffer); + item.setData( + XQConversions::s60DescToQString( + subjectBuffer), Subject); + subjectBuffer.Close(); + } + + RBuf bodyBuffer; + if (bodyBuffer.Create( + sqlSelectStmt.ColumnSize( + bodyIndex)) == KErrNone) + { + sqlSelectStmt.ColumnText(bodyIndex, bodyBuffer); + item.setData( + XQConversions::s60DescToQString( + bodyBuffer), BodyText); + bodyBuffer.Close(); + } + + RBuf previewPathBuffer; + QString attachmentPath; + if (previewPathBuffer.Create( + sqlSelectStmt.ColumnSize( + previewPathIndex)) == KErrNone) + { + sqlSelectStmt.ColumnText( + previewPathIndex, + previewPathBuffer); + + //Rightnow set inside attachments + attachmentPath = XQConversions::s60DescToQString( + previewPathBuffer); + item.setData(attachmentPath, Attachments); + previewPathBuffer.Close(); + } + + int msgProperty = 0; + msgProperty = sqlSelectStmt.ColumnInt(msgpropertyIndex); + item.setData(msgProperty, MessageProperty); + + RSqlColumnReadStream stream; + //Get data from binary column BLOB + TInt err = stream.ColumnBinary(sqlSelectStmt, + previewIconIndex); + + QCRITICAL_WRITE_FORMAT("Error from ColumnBinary()", err) + + if (err == KErrNone) + { + CFbsBitmap *bitmap = new CFbsBitmap; + TRAPD(err,bitmap->InternalizeL(stream)); + QCRITICAL_WRITE_FORMAT("Error from bitmap InternalizeL()", err) + + //convert bitmap to pixmap + if (err == KErrNone) + { + TSize size = bitmap->SizeInPixels(); + int bytesPerLine = bitmap->ScanLineLength( + size.iWidth, bitmap->DisplayMode()); + const uchar* dataPtr = + (const uchar*) bitmap->DataAddress(); + + QPixmap pixmap = QPixmap::fromImage(QImage( + dataPtr, size.iWidth, size.iHeight, + bytesPerLine, QImage::Format_RGB16)); + + setPreviewIcon(pixmap, attachmentPath, msgId, + true); + + } + //remove bitmap + delete bitmap; + } + + //set flag to disable fallback option + isEntryInDb = true; + } + } + } + sqlSelectStmt.Close(); + } + + //fallback option incase of db operation failure or enry not found in DB + //populate from data plugins + if (!isEntryInDb || err != KErrNone) + { + int error = iMmsDataPlugin->setMessageId(entry.EntryId()); + if(error != KErrNone) + { + // skip all + return; + } + int msgProperty = 0; + + if (iMmsDataPlugin->attachmentCount() > 0) + { + msgProperty |= EPreviewAttachment; + } + + if(validateMsgForForward(entry.EntryId())) + { + msgProperty |= EPreviewForward; + } + + //subject + item.setData(iMmsDataPlugin->subject(), Subject); + + int slideCount = iMmsDataPlugin->slideCount(); + bool isBodyTextSet = false; + bool isAudioSet = false; + bool isImageSet = false; + bool isVideoSet = false; + QString textContent; + QString videoPath; + QString imagePath; + + for (int i = 0; i < slideCount; ++i) + { + UniMessageInfoList objectList = iMmsDataPlugin->slideContent(i); + for (int index = 0; index < objectList.count(); ++index) + { + if (!isBodyTextSet && objectList[index]->mimetype().contains( + "text")) + { + QFile file(objectList[index]->path()); + file.open(QIODevice::ReadOnly); + QByteArray textArray; + textArray = file.readAll(); + char *data = new char[textArray.size()+1]; + strcpy(data,textArray.data()); + //This is needed since MMS text content + //is stored in UTF8 format + textContent = textContent.fromUtf8(data,strlen(data)); + delete []data; + item.setData(textContent, BodyText); + isBodyTextSet = true; + file.close(); + } + if (!isVideoSet && !isImageSet && objectList[index]->mimetype().contains( + "image")) + { + isImageSet = true; + msgProperty |= EPreviewImage; + if (objectList[index]->isProtected()) + { + msgProperty |= EPreviewProtectedImage; + } + if (objectList[index]->isCorrupted()) + { + msgProperty |= EPreviewCorruptedImage; + } + imagePath = objectList[index]->path(); + } + if (!isVideoSet && !isAudioSet && objectList[index]->mimetype().contains( + "audio")) + { + msgProperty |= EPreviewAudio; + if (objectList[index]->isProtected()) + { + msgProperty |= EPreviewProtectedAudio; + } + if (objectList[index]->isCorrupted()) + { + msgProperty |= EPreviewCorruptedAudio; + } + isAudioSet = true; + } + if (!( isImageSet || isAudioSet) && !isVideoSet && objectList[index]->mimetype().contains( + "video")) + { + isVideoSet = true; + msgProperty |= EPreviewVideo; + if (objectList[index]->isProtected()) + { + msgProperty |= EPreviewProtectedVideo; + } + if (objectList[index]->isCorrupted()) + { + msgProperty |= EPreviewCorruptedVideo; + } + videoPath = objectList[index]->path(); + } + } + foreach(UniMessageInfo* slide,objectList) + { + delete slide; + } + } + QPixmap pixmap; + //populate item with the attachment list + //TODO: This code is not required bcoz video icon is show and not preview + if (isVideoSet) + { + item.setData(videoPath, Attachments); + // Store thumbnail only for non protected, non corrupted content. + if (!(EPreviewProtectedVideo & msgProperty) && + !(EPreviewCorruptedVideo & msgProperty)) + { + setPreviewIcon(pixmap, videoPath, msgId, false); + } + } + else if (isImageSet) + { + item.setData(imagePath, Attachments); + // Store thumbnail only for non protected, non corrupted content. + if (!(EPreviewProtectedImage & msgProperty) && + !(EPreviewCorruptedImage & msgProperty)) + { + setPreviewIcon(pixmap, imagePath, msgId, false); + } + } + //populate msgProperty + item.setData(msgProperty, MessageProperty); + } + + // fill other attributes + if (entry.IsAttributeSet(ECsAttributeHighPriority)) + { + item.setData(ConvergedMessage::High, MessagePriority); + } + else if (entry.IsAttributeSet(ECsAttributeLowPriority)) + { + item.setData(ConvergedMessage::Low, MessagePriority); + } +} + +//--------------------------------------------------------------- +// ConversationsModel::handleMMSNotification +// @see header +//--------------------------------------------------------------- +void ConversationsModel::handleMMSNotification(QStandardItem& item, + const CCsConversationEntry& entry) +{ + // set context to current entry + TRAPD(err, mMsgStoreHandler->setNotificationMessageIdL(entry.EntryId())); + if(err != KErrNone) + { + return; + } + + // fetch relevent info to show in CV + // notification state e.g. waiting, retrieving etc + QString statusStr; + int status; + mMsgStoreHandler->NotificationStatus(status, statusStr); + + // create data for bodytext role + QString dataText; + dataText.append(mMsgStoreHandler->NotificationMsgSize()); + dataText.append(QChar::LineSeparator); + dataText.append(mMsgStoreHandler->NotificationClass()); + dataText.append(QChar::LineSeparator); + dataText.append(mMsgStoreHandler->NotificationExpiryDate()); + if(!statusStr.isEmpty()) + { + dataText.append(QChar::LineSeparator); + dataText.append(statusStr); + } + + // set fetched data to roles + item.setData(status, NotificationStatus); + item.setData(dataText, BodyText); + + if (entry.IsAttributeSet(ECsAttributeHighPriority)) { + item.setData(ConvergedMessage::High, MessagePriority); + } + else if (entry.IsAttributeSet(ECsAttributeLowPriority)) { + item.setData(ConvergedMessage::Low, MessagePriority); + } +} + +//--------------------------------------------------------------- +// ConversationsModel::handleBlueToothMessages +// @see header +//--------------------------------------------------------------- +void ConversationsModel::handleBlueToothMessages(QStandardItem& item, + const CCsConversationEntry& entry) + { + int msgSubType = ConversationsEngineUtility::messageSubType( + entry.GetType()); + + if (msgSubType == ConvergedMessage::VCard) + { + handleVCard(item, entry.EntryId()); + } + else + { + QString description = XQConversions::s60DescToQString( + *(entry.Description())); + + if (msgSubType == ConvergedMessage::VCal) // "vCalendar" + { + //message sub-type + item.setData(ConvergedMessage::VCal, MessageSubType); + } + else + { + //message sub-type + item.setData(ConvergedMessage::None, MessageSubType); + } + //for BT messages we show filenames for all other (except vcard) messages + //get filename and set as body + QFileInfo fileinfo(description); + QString filename = fileinfo.fileName(); + item.setData(filename, BodyText); + } + } + +//--------------------------------------------------------------- +// ConversationsModel::handleBioMessages +// @see header +//--------------------------------------------------------------- +void ConversationsModel::handleBioMessages(QStandardItem& item, const CCsConversationEntry& entry) +{ + int msgSubType = ConversationsEngineUtility::messageSubType(entry.GetType()); + if (ConvergedMessage::VCard == msgSubType) + { + handleVCard(item, entry.EntryId()); + } + else if (ConvergedMessage::VCal == msgSubType) { + //not supported + } + else if (ConvergedMessage::RingingTone == msgSubType) { + iBioMsgPlugin->setMessageId(entry.EntryId()); + if (iBioMsgPlugin->attachmentCount() > 0) { + UniMessageInfoList attList = iBioMsgPlugin->attachmentList(); + QString attachmentPath = attList[0]->path(); + + //get tone title, and set as bodytext + RingBc ringBc; + item.setData(ringBc.toneTitle(attachmentPath), BodyText); + while (!attList.isEmpty()) { + delete attList.takeFirst(); + } + } + + } + else { + // description + HBufC* description = entry.Description(); + QString subject(""); + if (description && description->Length()) { + subject = (XQConversions::s60DescToQString(*description)); + item.setData(subject, BodyText); + } + } +} + +//--------------------------------------------------------------- +// ConversationsModel::getDBHandle() +// @see header +//--------------------------------------------------------------- +RSqlDatabase& ConversationsModel::getDBHandle(TBool& isOpen) +{ + isOpen = iSqlDbOpen; + return iSqlDb; +} + +//--------------------------------------------------------------- +// ConversationsModel::setPreviewIcon() +// @see header +//--------------------------------------------------------------- +void ConversationsModel::setPreviewIcon(QPixmap& pixmap, QString& filePath, + int msgId, bool inDb) +{ + + //Since the population happens in reverse this check is needed so that + //most recent items have their icons present in cache + if (previewIconCache.totalCost() >= previewIconCache.maxCost()) + return; + + // if not found in db, set from file path + if (!inDb) + { + QPixmap pixmap(filePath); + QPixmap scaledPixmap = pixmap.scaled(KWidth, KHeight, Qt::IgnoreAspectRatio); + HbIcon *previewIcon = new HbIcon(scaledPixmap); + + previewIconCache.insert(msgId, previewIcon); + + } + else + { + HbIcon *previewIcon = new HbIcon(pixmap); + previewIconCache.insert(msgId, previewIcon); + } +} + +//--------------------------------------------------------------- +// ConversationsModel::getPreviewIconItem() +// @see header +//--------------------------------------------------------------- +HbIcon* ConversationsModel::getPreviewIconItem(int msgId, + QString& filepath) const +{ + QCRITICAL_WRITE("ConversationsModel::getPreviewIconItem start.") + + //Initialize icon from the Cache will be NULL if Item not present + HbIcon* previewIcon = previewIconCache[msgId]; + if (!previewIcon) + { + //This is done in this way as non-const function call cant be done here + emit retrievePreviewIcon(msgId, filepath); + + previewIcon = previewIconCache[msgId]; + } + + QCRITICAL_WRITE("ConversationsModel::getPreviewIconItem start.") + + return previewIcon; +} + +//--------------------------------------------------------------- +// ConversationsModel::updatePreviewIcon() +// @see header +//--------------------------------------------------------------- +void ConversationsModel::updatePreviewIcon(int msgId, QString& filePath) +{ + QCRITICAL_WRITE("ConversationsModel::updatePreviewIcon start.") + + //sql query to get preview-icon from DB + bool imagePreviewed = false; + QPixmap pixmap; + + if (iSqlDbOpen) + { + RSqlStatement sqlSelectPreviewIconStmt; + TInt err = sqlSelectPreviewIconStmt.Prepare(iSqlDb, + KSelectPreviewIconStmt); + + QCRITICAL_WRITE_FORMAT("Error from Prepare()", err) + + if (err == KErrNone) + { + //msg_id + TInt msgIdIndex = sqlSelectPreviewIconStmt.ParameterIndex( + _L(":message_id")); + sqlSelectPreviewIconStmt.BindInt(msgIdIndex, msgId); + + // get preview-icon from DB + err = sqlSelectPreviewIconStmt.Next(); + QCRITICAL_WRITE_FORMAT("Error from Next()", err) + + if (err == KSqlAtRow) + { + TInt previewIconIndex = sqlSelectPreviewIconStmt.ColumnIndex( + _L("preview_icon")); + + RSqlColumnReadStream stream; + + //Get data from binary column BLOB + err = stream.ColumnBinary(sqlSelectPreviewIconStmt, + previewIconIndex); + + QCRITICAL_WRITE_FORMAT("Error from ColumnBinary()", err) + + if (err == KErrNone) + { + CFbsBitmap *bitmap = new CFbsBitmap; + TRAPD(err,bitmap->InternalizeL(stream)); + QCRITICAL_WRITE_FORMAT("Error from bitmap InternalizeL()", err) + + //convert bitmap to pixmap + if (err == KErrNone) + { + TSize size = bitmap->SizeInPixels(); + int bytesPerLine = bitmap->ScanLineLength(size.iWidth, + bitmap->DisplayMode()); + const uchar* dataPtr = + (const uchar*) bitmap->DataAddress(); + + pixmap = QPixmap::fromImage(QImage(dataPtr, + size.iWidth, size.iHeight, bytesPerLine, + QImage::Format_RGB16)); + + imagePreviewed = true; + + QCRITICAL_WRITE("Bitmap Conversion completed") + } + //remove bitmap + delete bitmap; + } + //close stream + stream.Close(); + } + } + sqlSelectPreviewIconStmt.Close(); + } + + // if not found in db, set from file path + if (!imagePreviewed) + { + QPixmap orgPixmap(filePath); + pixmap = orgPixmap.scaled(63.65, 63.65, Qt::IgnoreAspectRatio); + } + HbIcon * previewIcon = new HbIcon(pixmap); + + previewIconCache.insert(msgId, previewIcon); + + QCRITICAL_WRITE("ConversationsModel::updatePreviewIcon end.") + +} + +//--------------------------------------------------------------- +// ConversationsModel::handleVCard() +// @see header +//--------------------------------------------------------------- +void ConversationsModel::handleVCard(QStandardItem& item, int msgId) + { + //sql query to get vcard-path from DB + bool vCardParsed = false; + + if (iSqlDbOpen) + { + RSqlStatement sqlSelectVcardStmt; + TInt err = sqlSelectVcardStmt.Prepare(iSqlDb, KSelectVCardStmt); + + QCRITICAL_WRITE_FORMAT("Error from Prepare()", err) + + if (err == KErrNone) + { + //msg_id + TInt msgIdIndex = sqlSelectVcardStmt.ParameterIndex( + _L(":message_id")); + sqlSelectVcardStmt.BindInt(msgIdIndex, msgId); + // state + TInt msgProcessingStateIndex = sqlSelectVcardStmt.ColumnIndex( + _L("msg_processingstate")); + + // get vacrd-path from DB + err = sqlSelectVcardStmt.Next(); + QCRITICAL_WRITE_FORMAT("Error from Next()", err) + + if (err == KSqlAtRow) + { + int msgProcessingState = 0; + msgProcessingState = sqlSelectVcardStmt.ColumnInt( + msgProcessingStateIndex); + if (msgProcessingState == EPreviewMsgProcessed) + { + //path-index + TInt previewPathIndex = sqlSelectVcardStmt.ColumnIndex( + _L("preview_path")); + + //Get vcard-path data from path-index + RSqlColumnReadStream stream; + err = stream.ColumnBinary(sqlSelectVcardStmt, + previewPathIndex); + + QCRITICAL_WRITE_FORMAT("Error from ColumnBinary()", err) + + if (err == KErrNone) + { + RBuf vCardPathBuffer; + if (vCardPathBuffer.Create( + sqlSelectVcardStmt.ColumnSize( + previewPathIndex)) == KErrNone) + { + sqlSelectVcardStmt.ColumnText( + previewPathIndex, + vCardPathBuffer); + + //set inside attachments + QString attachmentPath( + XQConversions::s60DescToQString( + vCardPathBuffer)); + item.setData(attachmentPath, Attachments); + + //get display-name and set as bodytext + QString displayName = + MsgContactHandler::getVCardDisplayName( + attachmentPath); + item.setData(displayName, BodyText); + + vCardPathBuffer.Close(); + vCardParsed = true; + + QCRITICAL_WRITE("vcard parsing complete.") + } + } + //close stream + stream.Close(); + } + } + } + sqlSelectVcardStmt.Close(); + } + + // fallback, if not parsed in DB, parse from store + if (!vCardParsed) + { + iBioMsgPlugin->setMessageId(msgId); + + if (iBioMsgPlugin->attachmentCount() > 0) + { + UniMessageInfoList attList = iBioMsgPlugin->attachmentList(); + QString attachmentPath = attList[0]->path(); + + //get display-name and set as bodytext + QString displayName = MsgContactHandler::getVCardDisplayName( + attachmentPath); + item.setData(displayName, BodyText); + item.setData(attachmentPath, Attachments); + + // clear attachement list : its allocated at data model + while (!attList.isEmpty()) + { + delete attList.takeFirst(); + } + } + } + } + +//--------------------------------------------------------------- +// ConversationsModel::clearModel() +// @see header +//--------------------------------------------------------------- +void ConversationsModel::clearModel() +{ + clear(); + previewIconCache.clear(); +} + +//--------------------------------------------------------------- +// ConversationsModel::emitConversationViewEmpty() +// @see header +//--------------------------------------------------------------- +void ConversationsModel:: emitConversationViewEmpty() +{ + emit conversationViewEmpty(); +} +//EOF