emailuis/nmailuiengine/src/nmmessagelistmodel.cpp
branchRCL_3
changeset 63 d189ee25cf9d
equal deleted inserted replaced
61:dcf0eedfc1a3 63:d189ee25cf9d
       
     1 /*
       
     2 * Copyright (c) 2009 - 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include "nmuiengineheaders.h"
       
    19 
       
    20 static const int NmFolderTypeRole = Qt::UserRole+1; 
       
    21 
       
    22 /*!
       
    23     \class NmMessageListModel
       
    24     \brief The NmMessageListModel class represents data model for mailbox list.
       
    25     @alpha
       
    26 
       
    27     The NmMessageListModel class uses NmMessageEnvelope class to represent data returned in its'
       
    28     data method to get all information needed for one list row for a widget by calling the method
       
    29     once.
       
    30 */
       
    31 
       
    32 /*!
       
    33 	Class constructor.
       
    34 */
       
    35 NmMessageListModel::NmMessageListModel(NmDataManager &dataManager,
       
    36                                        QObject *parent /* = 0 */)
       
    37 : QStandardItemModel(parent),
       
    38   mDataManager(dataManager),
       
    39   mDividersActive(false),
       
    40   mParentPtr(NULL),
       
    41   mCurrentFolderType(NmFolderInbox),
       
    42   mIgnoreFolderIds(false)
       
    43 {
       
    44     NM_FUNCTION;
       
    45     
       
    46     // Check for setting whether dividers are active
       
    47     // mDividersActive = ...
       
    48     // update also the test cases
       
    49 }
       
    50 
       
    51 
       
    52 /*!
       
    53 	Class destructor.
       
    54 */
       
    55 NmMessageListModel::~NmMessageListModel()
       
    56 {
       
    57     NM_FUNCTION;
       
    58     
       
    59     clear();
       
    60 }
       
    61 
       
    62 
       
    63 /*!
       
    64     Returns data specified by \a index. Only Qt::DisplayRole is supported in \a role.
       
    65     The refresh method must have been called before this method can return any real data.
       
    66 */
       
    67 QVariant NmMessageListModel::data(const QModelIndex &index, int role) const
       
    68 {
       
    69     NM_FUNCTION;
       
    70     
       
    71     QVariant qVariant;
       
    72 
       
    73     if (index.isValid()){
       
    74         if (role == Qt::DisplayRole) {
       
    75             NmMessageListModelItem *item =
       
    76                 static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
    77             qVariant = QVariant::fromValue(item);
       
    78         }
       
    79         else if (role == NmFolderTypeRole) {
       
    80             qVariant = QVariant(mCurrentFolderType);
       
    81         }    
       
    82     }
       
    83 
       
    84     return qVariant;
       
    85 }
       
    86 
       
    87 
       
    88 /*!
       
    89     This refreshes the data of the model.
       
    90 
       
    91     \param mailboxId The ID of the mailbox.
       
    92     \param folderId The ID of the folder.
       
    93     \param messageEnvelopeList A list containing the message meta data.
       
    94 */
       
    95 void NmMessageListModel::refresh(
       
    96         const NmId mailboxId, 
       
    97         const NmId folderId,
       
    98         const QList<NmMessageEnvelope*> &messageEnvelopeList)
       
    99 {
       
   100     NM_FUNCTION;
       
   101 
       
   102     // Store the current mailbox and folder IDs.
       
   103     mCurrentMailboxId = mailboxId;
       
   104     mCurrentFolderId = folderId;
       
   105 
       
   106     // Store the type of the currently displayed folder.
       
   107     mCurrentFolderType = mDataManager.folderTypeById(mailboxId, folderId);
       
   108 
       
   109     // Clear the model.
       
   110     clear();
       
   111 
       
   112     // Add the items from the given list.
       
   113     NmMessageEnvelope* insertedMessage(NULL);
       
   114     int parentCount(0);
       
   115     int childCount(0);
       
   116 
       
   117     for (int i(0); i < messageEnvelopeList.count(); i++) {
       
   118         NmMessageEnvelope *nextMessage = messageEnvelopeList[i];
       
   119         // imap and pop is using common sent, outbox or draft folder
       
   120         // for all mailboxes, here we want to filter out messages that
       
   121         // are not under this mailbox
       
   122         bool insert(true);
       
   123         if (nextMessage 
       
   124             && (NmFolderSent == mCurrentFolderType
       
   125              || NmFolderOutbox == mCurrentFolderType
       
   126              || NmFolderDrafts == mCurrentFolderType)) {
       
   127             insert = (mCurrentMailboxId == nextMessage->mailboxId());  
       
   128         }
       
   129         if (insert) {
       
   130             if (mDividersActive &&
       
   131                 !messagesBelongUnderSameDivider(insertedMessage, nextMessage)) {
       
   132                 insertDividerIntoModel(nextMessage, parentCount);
       
   133                 parentCount++;
       
   134                 childCount = 0;
       
   135             }
       
   136     
       
   137             insertMessageIntoModel(nextMessage, childCount, false);
       
   138             insertedMessage = nextMessage;
       
   139             childCount++;
       
   140         }
       
   141     }
       
   142 }
       
   143 
       
   144 
       
   145 /*!
       
   146     insertDividerIntoModel. Function inserts divider into model.
       
   147 */
       
   148 void NmMessageListModel::insertDividerIntoModel(
       
   149     NmMessageEnvelope *messageForDivider,
       
   150     int parentRow)
       
   151 {
       
   152     NM_FUNCTION;
       
   153     
       
   154     mParentPtr = createTitleDividerItem(messageForDivider);
       
   155     insertRow(parentRow,mParentPtr);
       
   156     mParentPtr->callEmitDataChanged();
       
   157 }
       
   158 
       
   159 /*!
       
   160     Function inserts message into model. Message can be inserted
       
   161     either to root or to parent. If parent is zero, item is added into root.
       
   162 */
       
   163 void NmMessageListModel::insertMessageIntoModel(
       
   164 		NmMessageEnvelope *messageEnvelope, int childRow, bool emitSignal)
       
   165 {
       
   166     NM_FUNCTION;
       
   167     
       
   168     NmMessageListModelItem *mailItem = createMessageItem(messageEnvelope);
       
   169     if (mParentPtr) {
       
   170         // Add under parent divider
       
   171         mParentPtr->insertRow(childRow, mailItem);
       
   172     }
       
   173     else {
       
   174         // No dividers, add under root item
       
   175         insertRow(childRow,mailItem);
       
   176     }
       
   177     if (emitSignal) {
       
   178         mailItem->callEmitDataChanged();
       
   179     }
       
   180 }
       
   181 
       
   182 /*!
       
   183     Function checks whether the messages can be drawn under same title divider
       
   184     Check is done depending of the current sorting criteria
       
   185 */
       
   186 bool NmMessageListModel::messagesBelongUnderSameDivider(
       
   187     const NmMessageEnvelope *message1,
       
   188     const NmMessageEnvelope *message2) const
       
   189 {
       
   190     NM_FUNCTION;
       
   191     
       
   192     bool retVal(false);
       
   193     // First check pointer validity
       
   194     if (message1 && message2) {
       
   195         // Switch here for other sort modes 
       
   196         // Date based comparison
       
   197         QDateTime sentTime1 = message1->sentTime().toLocalTime();
       
   198         QDateTime sentTime2 = message2->sentTime().toLocalTime();
       
   199         if ( sentTime1.date() == sentTime2.date()) {
       
   200             retVal = true;
       
   201         }
       
   202     }
       
   203     return retVal;
       
   204 }
       
   205 
       
   206 
       
   207 /*!
       
   208     Handles the message events.
       
   209 
       
   210     \param event The type of the message event.
       
   211     \param folderId The folder containing the message.
       
   212     \param messageIds A list of message IDs related to the event.
       
   213 */
       
   214 void NmMessageListModel::handleMessageEvent(NmMessageEvent event,
       
   215                                             const NmId &folderId,
       
   216                                             const QList<NmId> &messageIds,
       
   217                                             const NmId &mailboxId)
       
   218 {
       
   219     NM_FUNCTION;
       
   220     const int idCount = messageIds.count();
       
   221 
       
   222     // Folder ID does not concern us if this model instance is used for e.g.
       
   223     // searching messages.
       
   224     if (!mIgnoreFolderIds) {
       
   225         if (folderId == 0) {
       
   226             // Const cast is used here because also the input parameter has to
       
   227             // be changed.
       
   228             const_cast<NmId&>(folderId) =
       
   229                 mDataManager.getStandardFolderId(mailboxId, NmFolderInbox);
       
   230             NmUiStartParam *startParam =
       
   231                 new NmUiStartParam(NmUiViewMessageList, mailboxId, folderId);
       
   232             emit setNewParam(startParam);
       
   233         }
       
   234 
       
   235         if (mCurrentFolderId == 0) {
       
   236             // Folder ID was not known at time when the mailbox opened and we
       
   237             // know that because of events the subscription is valid only for
       
   238             // the current mailbox.
       
   239             mCurrentFolderId = folderId; 
       
   240         }
       
   241         // MailboxId checking here is done because we want to filter out messages
       
   242         // that belongs to other mailboxes in case of imap/pop sent, outbox or draft folder
       
   243         if (mCurrentFolderId != folderId || mCurrentMailboxId != mailboxId) {
       
   244             // The event does not concern the folder currently being displayed.
       
   245             // Thus, ignore it.
       
   246             return;
       
   247         }
       
   248     }
       
   249 
       
   250     // Go through the given message IDs and do the appropriate operations
       
   251     // according to the type of the event.
       
   252     for (int i(0); i < idCount; ++i) {
       
   253         switch (event) {
       
   254             case NmMessageChanged: {
       
   255                 updateMessageEnvelope(mailboxId, folderId, messageIds[i]);
       
   256                 break;
       
   257             }
       
   258             case NmMessageCreated: {
       
   259                 // mIgnoreFolderIds is true if (and only if) this model is used
       
   260                 // for mail search purposes and thus, we do not want the model
       
   261                 // to handle "message created" events. Issue to consider:
       
   262                 // renaming mIgonreFolderIds => mModelUsedForSearch or something
       
   263                 // similar.
       
   264                 if (!mIgnoreFolderIds && !itemFromModel(messageIds[i])) {
       
   265                     insertNewMessageIntoModel(mailboxId, folderId, messageIds[i]);
       
   266                 }
       
   267                 
       
   268                 break;
       
   269             }
       
   270             case NmMessageFound: {
       
   271                 if (!itemFromModel(messageIds[i])) {
       
   272                     insertNewMessageIntoModel(mailboxId, folderId, messageIds[i]);
       
   273                 }
       
   274 
       
   275                 break;
       
   276             }
       
   277             case NmMessageDeleted: {
       
   278                 removeMessageFromModel(messageIds[i]);
       
   279                 break;
       
   280             }
       
   281         }
       
   282     }
       
   283 }
       
   284 
       
   285 
       
   286 /*!
       
   287     Function inserts new message into correct position to model.
       
   288     A new title divider is created if it is needed.
       
   289 */
       
   290 void NmMessageListModel::insertNewMessageIntoModel(
       
   291     const NmId &mailboxId,
       
   292     const NmId &folderId,
       
   293     const NmId &msgId)
       
   294 {
       
   295     NM_FUNCTION;
       
   296     
       
   297     // envelope ownership is here
       
   298     NmMessageEnvelope *newMsgEnve = mDataManager.envelopeById(mailboxId, folderId, msgId);
       
   299     if (newMsgEnve) {
       
   300         int rowIndex(getInsertionIndex(*newMsgEnve));
       
   301         if (!mDividersActive) {
       
   302             if (rowIndex > -1){
       
   303                 insertMessageIntoModel(newMsgEnve, rowIndex, true);
       
   304             } else {
       
   305                 NmMessageListModelItem *mailItem = createMessageItem(newMsgEnve);
       
   306                 appendRow(mailItem);
       
   307                 mailItem->callEmitDataChanged();
       
   308             }
       
   309         } else {
       
   310             // model contain items, message goes to the middle of the list
       
   311             if (rowIndex > 0) {
       
   312                 int dividerIndex(0);
       
   313                 QList<QStandardItem*> items = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
       
   314                 QModelIndex index = items[rowIndex]->index();
       
   315                 NmMessageListModelItem *item = static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
   316                 NmMessageEnvelope *replacedEnve = item->envelopePtr();
       
   317                 if (messagesBelongUnderSameDivider(newMsgEnve,replacedEnve)) {
       
   318                     // find the index of the divider and insert message as child object
       
   319                     // dividerIndex is not actually used here but function sets
       
   320                     // the correct parent pointer
       
   321                     dividerIndex = dividerInsertionIndex(rowIndex);
       
   322                     insertMessageIntoModel(newMsgEnve, 0, true);
       
   323                 } else {
       
   324                     // create new divider and find the correct index for it
       
   325                     dividerIndex = dividerInsertionIndex(rowIndex);
       
   326                     insertDividerIntoModel(newMsgEnve, dividerIndex);
       
   327                     // Insert message as a first child under new divider
       
   328                     insertMessageIntoModel(newMsgEnve, 0, true);
       
   329                 }
       
   330                 items.clear();
       
   331             }
       
   332             // first mail item in the model,
       
   333             // insert new divider to index 0 and new message as a child.
       
   334             else if (0 == rowIndex) {
       
   335                 insertDividerIntoModel(newMsgEnve, rowIndex);
       
   336                 insertMessageIntoModel(newMsgEnve, 0, true);
       
   337             }
       
   338             // this will go to the last item of the list and create new title divider
       
   339             else {
       
   340                 mParentPtr = createTitleDividerItem(newMsgEnve);
       
   341                 appendRow(mParentPtr);
       
   342                 mParentPtr->callEmitDataChanged();
       
   343                 NmMessageListModelItem *mailItem = createMessageItem(newMsgEnve);
       
   344                 // Add under parent divider
       
   345                 mParentPtr->appendRow(mailItem);
       
   346                 mailItem->callEmitDataChanged();
       
   347             }
       
   348         }
       
   349     }
       
   350     delete newMsgEnve;
       
   351 }
       
   352 
       
   353 /*!
       
   354     Function check model index in which the new message should be inserted
       
   355     with the currently active sort mode.
       
   356 */
       
   357 int NmMessageListModel::getInsertionIndex(
       
   358     const NmMessageEnvelope &envelope) const
       
   359 {
       
   360     NM_FUNCTION;
       
   361     
       
   362     int ret(NmNotFoundError);
       
   363     
       
   364     // Date+descending sort mode based comparison.
       
   365     // Go through model and compare sent times with QDateTime >= comparison operation.
       
   366     QList<QStandardItem*> items = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
       
   367     int count(items.count());
       
   368     bool found(false);
       
   369     int i(0);
       
   370     while (i < count && !found) {
       
   371         QModelIndex index = items[i]->index();
       
   372         NmMessageListModelItem *item = static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
   373         if (NmMessageListModelItem::NmMessageItemMessage == item->itemType()) {
       
   374         	found = envelope.sentTime() >= item->envelope().sentTime();
       
   375         	if (found) {
       
   376                 ret = i;
       
   377         	}
       
   378         }
       
   379         i++;
       
   380     }
       
   381     if (0 == count) {
       
   382         ret = NmNoError;
       
   383     }
       
   384     items.clear();
       
   385     return ret;
       
   386 }
       
   387 
       
   388 /*!
       
   389     Function finds preceding title divider index and sets the
       
   390     mParentPtr variable.
       
   391 */
       
   392 int NmMessageListModel::dividerInsertionIndex(int messageIndex)
       
   393 {
       
   394     NM_FUNCTION;
       
   395     
       
   396     bool found(false);
       
   397     int ret(NmNoError);
       
   398     QModelIndex index;
       
   399     QList<QStandardItem*> items = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
       
   400     for (int i = messageIndex-1; i >= 0 && !found; i--) {
       
   401         index = items[i]->index();
       
   402         NmMessageListModelItem *item = static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
   403         if(item->itemType() == NmMessageListModelItem::NmMessageItemTitleDivider) {
       
   404             found = true;
       
   405             mParentPtr = static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
   406             ret = index.row();
       
   407         }
       
   408     }
       
   409     items.clear();
       
   410     return ret;
       
   411 }
       
   412 
       
   413 /*!
       
   414     Create title divider item
       
   415 */
       
   416 NmMessageListModelItem *NmMessageListModel::createTitleDividerItem(
       
   417 		NmMessageEnvelope *messageForDivider)
       
   418 {
       
   419     NM_FUNCTION;
       
   420     
       
   421     NmMessageListModelItem *item = new NmMessageListModelItem();
       
   422     item->setItemType(NmMessageListModelItem::NmMessageItemTitleDivider);
       
   423 
       
   424     QDate sentLocalDate = messageForDivider->sentTime().toLocalTime().date();
       
   425     QDate currentdate = QDate::currentDate();
       
   426 
       
   427     if (sentLocalDate == currentdate) {
       
   428         // NOTE: when dividers are taken in to use hbTrId macro should used here,
       
   429         // to be clarified how to access ts-file (located under ui component)
       
   430         item->setTitleDivider(tr("Today", "txt_nmailuiengine_divider_today"));
       
   431         item->setText(tr("Today", "txt_nmailuiengine_divider_today"));
       
   432     }
       
   433     else {
       
   434         QLocale locale;
       
   435         QString divider = locale.toString(sentLocalDate, QLocale::LongFormat);
       
   436         item->setTitleDivider(divider);
       
   437         item->setText(divider);
       
   438         }
       
   439     item->setEnvelope(*messageForDivider);
       
   440     item->setData(Hb::ParentItem, Hb::ItemTypeRole);
       
   441     return item;
       
   442 }
       
   443 
       
   444 /*!
       
   445     Create message item
       
   446 */
       
   447 NmMessageListModelItem *NmMessageListModel::createMessageItem(
       
   448 		NmMessageEnvelope *envelope)
       
   449 {
       
   450     NM_FUNCTION;
       
   451     
       
   452     NmMessageListModelItem *mailItem = new NmMessageListModelItem();
       
   453     mailItem->setEnvelope(*envelope);
       
   454     mailItem->setItemType(NmMessageListModelItem::NmMessageItemMessage);
       
   455     mailItem->setData(Hb::StandardItem, Hb::ItemTypeRole);
       
   456     return mailItem;
       
   457 }
       
   458 
       
   459 /*!
       
   460     Returns divider state
       
   461 */
       
   462 bool NmMessageListModel::dividersActive()
       
   463 {
       
   464     NM_FUNCTION;
       
   465     
       
   466     return mDividersActive;
       
   467 }
       
   468 
       
   469 /*!
       
   470     Set divider state
       
   471 */
       
   472 void NmMessageListModel::setDividers(bool active)
       
   473 {
       
   474     NM_FUNCTION;
       
   475     
       
   476     mDividersActive = active;
       
   477 }
       
   478 
       
   479 /*!
       
   480    Change item property if differs
       
   481 */
       
   482 void NmMessageListModel::setEnvelopeProperties(
       
   483     NmEnvelopeProperties property,
       
   484     const QList<NmId> &messageIds)
       
   485 {
       
   486     NM_FUNCTION;
       
   487     
       
   488     for (int i(0); i < messageIds.count(); i++) {
       
   489         updateEnvelope(property, messageIds[i]);
       
   490     }
       
   491 }
       
   492 
       
   493 
       
   494 /*!
       
   495     Returns the ID of the current mailbox.
       
   496 */
       
   497 NmId NmMessageListModel::currentMailboxId()
       
   498 {
       
   499     NM_FUNCTION;
       
   500     
       
   501     return mCurrentMailboxId;
       
   502 }
       
   503 
       
   504 
       
   505 /*!
       
   506     Sets whether the model should ignore the folder IDs or not. The folder IDs
       
   507     should be ignored e.g. when the model is used for searching messages
       
   508     (i.e. used by the search view).
       
   509 
       
   510     \param ignore If true, will ignore the folder IDs.
       
   511 */
       
   512 void NmMessageListModel::setIgnoreFolderIds(bool ignore)
       
   513 {
       
   514     NM_FUNCTION;
       
   515     
       
   516     mIgnoreFolderIds = ignore;
       
   517 }
       
   518 
       
   519 
       
   520 /*!
       
   521    Remove message from model if message exists in model
       
   522 */
       
   523 void NmMessageListModel::removeMessageFromModel(const NmId &msgId)
       
   524 {
       
   525     NM_FUNCTION;
       
   526     
       
   527     QList<QStandardItem*> items = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
       
   528     int count(items.count());
       
   529     bool found(false);
       
   530     int i(0);
       
   531     while (!found && i < count) {
       
   532         QModelIndex index = items[i]->index();
       
   533         NmMessageListModelItem *item = static_cast<NmMessageListModelItem*>(itemFromIndex(index));
       
   534         if (NmMessageListModelItem::NmMessageItemMessage == item->itemType()
       
   535                 && msgId == item->envelope().messageId()) {
       
   536             found = true;
       
   537             // dividers are not active, just remove message
       
   538             if (!mDividersActive) {
       
   539                 removeItem(index.row(), *item);
       
   540             } else {
       
   541                 // check the type from previous item
       
   542                 QModelIndex prevIndex = items[i-1]->index();
       
   543                 NmMessageListModelItem* previous = static_cast<NmMessageListModelItem*>(itemFromIndex(prevIndex));
       
   544                 if (NmMessageListModelItem::NmMessageItemTitleDivider == previous->itemType()) {
       
   545                     // previous item is title divider
       
   546                     if (i < (count-1)) {
       
   547                         // if this is not last item in the list, check next item
       
   548                         QModelIndex nextIndex = items[i+1]->index();
       
   549                         NmMessageListModelItem* next = static_cast<NmMessageListModelItem*>(itemFromIndex(nextIndex));
       
   550                         if (NmMessageListModelItem::NmMessageItemMessage == next->itemType()) {
       
   551                             // next item is message, divider should not be removed
       
   552                             removeItem(index.row(), *item);
       
   553                         } else {
       
   554                             // next item is another divider, remove also divider
       
   555                             removeItem(index.row(), *item);
       
   556                             removeItem(prevIndex.row(), *previous);
       
   557                         }
       
   558                     } else {
       
   559                         // this is the last message in list, remove also divider
       
   560                         removeItem(index.row(), *item);
       
   561                         removeItem(prevIndex.row(), *previous);
       
   562                     }
       
   563                 }  else {
       
   564                     // previous item is message, title divider should not be deleted
       
   565                     removeItem(index.row(), *item);
       
   566                 }
       
   567             }
       
   568         }
       
   569         i++;
       
   570     }
       
   571     items.clear();
       
   572 }
       
   573 
       
   574 /*!
       
   575    Helper function to remove row
       
   576 */
       
   577 void NmMessageListModel::removeItem(int row, NmMessageListModelItem &item)
       
   578 {
       
   579     NM_FUNCTION;
       
   580     
       
   581     QStandardItem *parent = item.parent();
       
   582     removeRow(row, indexFromItem(parent));
       
   583 }
       
   584 
       
   585 /*!
       
   586    Search item from model
       
   587 */
       
   588 NmMessageListModelItem *NmMessageListModel::itemFromModel(const NmId &messageId)
       
   589 {
       
   590     NM_FUNCTION;
       
   591     
       
   592     QList<QStandardItem*> items = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
       
   593     int count(items.count());
       
   594     bool found(false);
       
   595     int i(0);
       
   596     NmMessageListModelItem *ret(NULL);
       
   597     while (i < count && !found) {
       
   598         NmMessageListModelItem *item =
       
   599             static_cast<NmMessageListModelItem*>(itemFromIndex(items[i]->index()));
       
   600         if (NmMessageListModelItem::NmMessageItemMessage == item->itemType()
       
   601             && messageId == item->envelope().messageId()) {
       
   602             found = true;
       
   603             ret = item;
       
   604         }
       
   605         i++;
       
   606     }
       
   607     return ret;
       
   608 }
       
   609 
       
   610 /*!
       
   611    Helper function for envelope comparison
       
   612 */
       
   613 bool NmMessageListModel::changed(const NmMessageEnvelope &first, const NmMessageEnvelope &second)
       
   614 {
       
   615     NM_FUNCTION;
       
   616     
       
   617     return first != second;
       
   618 }
       
   619 
       
   620 /*!
       
   621    Updates envelope if something is changed
       
   622 */
       
   623 void NmMessageListModel::updateMessageEnvelope(const NmId &mailboxId,
       
   624         const NmId &folderId,
       
   625         const NmId &msgId)
       
   626 {
       
   627     NM_FUNCTION;
       
   628     
       
   629     NmMessageListModelItem *item = itemFromModel(msgId);
       
   630     // envelope ownership is here
       
   631     NmMessageEnvelope *newEnvelope = mDataManager.envelopeById(mailboxId, folderId, msgId);
       
   632     if (item && newEnvelope) {
       
   633         if (changed(*item->envelopePtr(), *newEnvelope)) {
       
   634             // function takes envelope ownership 
       
   635             item->setEnvelope(newEnvelope);
       
   636         } else {
       
   637             delete newEnvelope;
       
   638             newEnvelope = NULL;
       
   639         }
       
   640     }
       
   641 }
       
   642 
       
   643 /*!
       
   644    Update envelope property
       
   645 */
       
   646 void NmMessageListModel::updateEnvelope(NmEnvelopeProperties property, const NmId &msgId)
       
   647 {
       
   648     NM_FUNCTION;
       
   649     
       
   650     NmMessageListModelItem *item = itemFromModel(msgId);
       
   651     if (item) {
       
   652         bool changed(false);
       
   653         NmMessageEnvelope *envelope = item->envelopePtr();
       
   654         switch (property)
       
   655         {
       
   656         case MarkAsRead:
       
   657         {
       
   658             if (!envelope->isRead()) {
       
   659                 envelope->setRead(true);
       
   660                 changed = true;
       
   661             }
       
   662             break;
       
   663         }
       
   664         case MarkAsUnread:
       
   665         {
       
   666             if (envelope->isRead()) {
       
   667                 envelope->setRead(false);
       
   668                 changed = true;
       
   669             }
       
   670             break;
       
   671         }
       
   672         default:
       
   673             break;
       
   674         }
       
   675         if (changed) {
       
   676             item->callEmitDataChanged();
       
   677         }
       
   678     }
       
   679 }