diff -r a32b19fb291e -r 5b14749788d7 messagingapp/msgui/appengine/src/conversationsmodel.cpp --- a/messagingapp/msgui/appengine/src/conversationsmodel.cpp Thu Jun 17 09:57:06 2010 +0100 +++ b/messagingapp/msgui/appengine/src/conversationsmodel.cpp Thu Jul 22 16:32:06 2010 +0100 @@ -19,26 +19,39 @@ #include "conversationsenginedefines.h" #include "conversationmsgstorehandler.h" #include "convergedmessage.h" -#include "s60qconversions.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, subject, body_text, preview_path, msg_property FROM conversation_messages WHERE message_id=:message_id "); +_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 "); +// 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 @@ -52,6 +65,11 @@ { 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); @@ -66,6 +84,9 @@ //Close SQL-DB iSqlDb.Close(); + //clear preview-cache + previewIconCache.clear(); + if (iDataModelPluginLoader) { delete iDataModelPluginLoader; iDataModelPluginLoader = NULL; @@ -146,6 +167,13 @@ 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); @@ -178,7 +206,7 @@ } case DisplayName: // Fall through start value = item->data(DisplayName); - break; + break; case Avatar: // Fall througn end value = item->data(Avatar); break; @@ -272,10 +300,10 @@ HBufC* description = entry.Description(); QString subject(""); if (description && description->Length()) { - subject = (S60QConversions::s60DescToQString(*description)); + subject = (XQConversions::s60DescToQString(*description)); } - // time stamp + // time stamp TTime unixEpoch(KUnixEpoch); TTimeIntervalSeconds seconds; TTime timeStamp(entry.TimeStamp()); @@ -285,7 +313,7 @@ //contact details HBufC* contact = entry.Contact(); if (contact && contact->Length()) { - item.setData(S60QConversions::s60DescToQString(*contact), ConversationAddress); + item.setData(XQConversions::s60DescToQString(*contact), ConversationAddress); } // message type. @@ -322,7 +350,7 @@ item.setData(ConvergedMessage::Outbox, MessageLocation); } - //message specific handling + //message specific handling if (msgType == ConvergedMessage::Mms) { QCRITICAL_WRITE("ConversationsModel::populateItem MMS start.") handleMMS(item, entry); @@ -347,6 +375,22 @@ } //--------------------------------------------------------------- +// 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 //--------------------------------------------------------------- @@ -357,7 +401,7 @@ bool isEntryInDb = false; TInt err = KErrNone; - + //check if db is open and query db if (iSqlDbOpen) { @@ -368,51 +412,100 @@ 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")); + _L("msg_property")); + TInt previewIconIndex = sqlSelectStmt.ColumnIndex( + _L("preview_icon")); err = sqlSelectStmt.BindInt(msgIdIndex, msgId); - + // populate item if ((KErrNone == err) && (sqlSelectStmt.Next() == KSqlAtRow)) { - RBuf subjectBuffer; - subjectBuffer.Create(sqlSelectStmt.ColumnSize(subjectIndex)); - sqlSelectStmt.ColumnText(subjectIndex, subjectBuffer); + 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; + subjectBuffer.Create(sqlSelectStmt.ColumnSize( + subjectIndex)); + sqlSelectStmt.ColumnText(subjectIndex, subjectBuffer); + + item.setData(XQConversions::s60DescToQString( + subjectBuffer), Subject); + subjectBuffer.Close(); - item.setData( - S60QConversions::s60DescToQString(subjectBuffer), - Subject); - subjectBuffer.Close(); + RBuf bodyBuffer; + bodyBuffer.Create(sqlSelectStmt.ColumnSize(bodyIndex)); + sqlSelectStmt.ColumnText(bodyIndex, bodyBuffer); + + item.setData( + XQConversions::s60DescToQString(bodyBuffer), + BodyText); + bodyBuffer.Close(); - RBuf bodyBuffer; - bodyBuffer.Create(sqlSelectStmt.ColumnSize(bodyIndex)); - sqlSelectStmt.ColumnText(bodyIndex, bodyBuffer); + RBuf previewPathBuffer; + previewPathBuffer.Create(sqlSelectStmt.ColumnSize( + previewPathIndex)); + sqlSelectStmt.ColumnText(previewPathIndex, + previewPathBuffer); - item.setData(S60QConversions::s60DescToQString(bodyBuffer), - BodyText); - bodyBuffer.Close(); + //Rightnow set inside attachments + QString attachmentPath(XQConversions::s60DescToQString( + previewPathBuffer)); + + item.setData(attachmentPath, Attachments); + previewPathBuffer.Close(); - RBuf previewPathBuffer; - previewPathBuffer.Create(sqlSelectStmt.ColumnSize( - previewPathIndex)); - sqlSelectStmt.ColumnText(previewPathIndex, previewPathBuffer); + 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) - //Rightnow set inside attachments - item.setData(S60QConversions::s60DescToQString( - previewPathBuffer), Attachments); - previewPathBuffer.Close(); + //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(); - int msgProperty = 0; - msgProperty = sqlSelectStmt.ColumnInt(msgpropertyIndex); - item.setData(msgProperty, MessageProperty); + QPixmap pixmap = QPixmap::fromImage(QImage( + dataPtr, size.iWidth, size.iHeight, + bytesPerLine, QImage::Format_RGB16)); + + setPreviewIcon(pixmap, attachmentPath, msgId, + true); - //set flag to disable fallback option - isEntryInDb = true; + } + //remove bitmap + delete bitmap; + } + + //set flag to disable fallback option + isEntryInDb = true; + } } } sqlSelectStmt.Close(); @@ -422,7 +515,12 @@ //populate from data plugins if (!isEntryInDb || err != KErrNone) { - iMmsDataPlugin->setMessageId(entry.EntryId()); + int error = iMmsDataPlugin->setMessageId(entry.EntryId()); + if(error != KErrNone) + { + // skip all + return; + } int msgProperty = 0; if (iMmsDataPlugin->attachmentCount() > 0) @@ -430,6 +528,11 @@ msgProperty |= EPreviewAttachment; } + if(validateMsgForForward(entry.EntryId())) + { + msgProperty |= EPreviewForward; + } + //subject item.setData(iMmsDataPlugin->subject(), Subject); @@ -457,24 +560,48 @@ isBodyTextSet = true; file.close(); } - if (!isImageSet && objectList[index]->mimetype().contains( + 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 (!isAudioSet && objectList[index]->mimetype().contains( + 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 (!isVideoSet && objectList[index]->mimetype().contains( + 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(); } } @@ -483,14 +610,28 @@ 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); @@ -520,28 +661,28 @@ { return; } - + // fetch relevent info to show in CV // msg size QString estimatedMsgSizeStr = QString("%1").arg(0); estimatedMsgSizeStr.append(" Kb"); - TRAP_IGNORE(estimatedMsgSizeStr = + TRAP_IGNORE(estimatedMsgSizeStr = mMsgStoreHandler->NotificationMsgSizeL()); - + // msg class type QString classInfoStr = mMsgStoreHandler->NotificationClass(); - + // notification expiry date //TODO: Need to do localization of digits used to show expiry time TTime expiryTime; QString expiryTimeStr; mMsgStoreHandler->NotificationExpiryDate(expiryTime, expiryTimeStr); - + // notification state e.g. waiting, retrieving etc QString statusStr; int status; mMsgStoreHandler->NotificationStatus(status, statusStr); - + // create data for bodytext role QString dataText; dataText.append("Size: "); // TODO: use logical str name @@ -580,7 +721,7 @@ { //TODO, needs to be revisited again, once BT team provides the solution for //BT received as Biomsg issue. - QString description = S60QConversions::s60DescToQString(*(entry.Description())); + QString description = XQConversions::s60DescToQString(*(entry.Description())); if (description.contains(".vcf") || description.contains(".ics")) // "vCard" { @@ -591,8 +732,8 @@ QString displayName = MsgContactHandler::getVCardDisplayName( description); item.setData(displayName, BodyText); - } - else + } + else { if (description.contains(".vcs")) // "vCalendar" { @@ -626,10 +767,11 @@ QString attachmentPath = attList[0]->path(); //get display-name and set as bodytext - QString displayName = + QString displayName = MsgContactHandler::getVCardDisplayName( attachmentPath); item.setData(displayName, BodyText); + item.setData(attachmentPath, Attachments); // clear attachement list : its allocated at data model while (!attList.isEmpty()) { @@ -659,7 +801,7 @@ HBufC* description = entry.Description(); QString subject(""); if (description && description->Length()) { - subject = (S60QConversions::s60DescToQString(*description)); + subject = (XQConversions::s60DescToQString(*description)); item.setData(subject, BodyText); } } @@ -674,4 +816,164 @@ 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::clearModel() +// @see header +//--------------------------------------------------------------- +void ConversationsModel::clearModel() +{ + clear(); + previewIconCache.clear(); +} + +void ConversationsModel:: emitConversationViewEmpty() +{ + emit conversationViewEmpty(); +} //EOF