phonebookengines/mobhistorymodel/src/mobhistorymodel.cpp
changeset 25 76a2435edfd4
parent 24 0ba2181d7c28
child 27 de1630741fbe
equal deleted inserted replaced
24:0ba2181d7c28 25:76a2435edfd4
     1 /*
       
     2 * Copyright (c) 2009 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 <QStringList>
       
    19 #include <QSqlDatabase>
       
    20 #include <QtAlgorithms>
       
    21 #ifndef PBK_UNIT_TEST
       
    22 #include <hbicon.h>
       
    23 #endif
       
    24 #include "mobhistorymodel_p.h"
       
    25 #include "mobhistorymodel.h"
       
    26 
       
    27 // Unnamed namespace for helper functions
       
    28 namespace
       
    29 {
       
    30     bool greaterThan(const TableRow& t1, const TableRow& t2)
       
    31     {
       
    32         return t1.timeStamp > t2.timeStamp;
       
    33     }
       
    34     
       
    35     bool lessThan(const TableRow& t1, const TableRow& t2)
       
    36     {
       
    37         return t1.timeStamp < t2.timeStamp;
       
    38     }
       
    39 }
       
    40 
       
    41 Q_DECLARE_METATYPE(LogsEvent *)
       
    42 
       
    43 /*!
       
    44  * Construct a new MobHistoryModel object to communicate 
       
    45  * with the conversations and logs databases.
       
    46  *
       
    47  * \param contactId History specific to this contact is cached. 
       
    48  * If no contact is specified all the call logs and conversation 
       
    49  * history from all contacts will be cached.
       
    50  */
       
    51 MobHistoryModel::MobHistoryModel(QContactLocalId contactId,
       
    52                                  QContactManager* manager,
       
    53                                  QObject *parent)
       
    54     : QAbstractListModel(parent)
       
    55 {
       
    56     d = new MobHistoryModelData(contactId, manager);
       
    57     
       
    58     // Check if the contact is my card
       
    59     if (d->m_contactId == d->m_contactManager->selfContactId()) {
       
    60         d->m_isMyCard = true;
       
    61     }
       
    62     else {
       
    63         d->m_isMyCard = false;
       
    64     }
       
    65     // Create the model structure and cache history data from the databases
       
    66     initializeModel();
       
    67 }
       
    68 
       
    69 MobHistoryModel::~MobHistoryModel()
       
    70 {
       
    71 }
       
    72 
       
    73 /*!
       
    74  * Return the data to be used by the view or delegates for a particular
       
    75  * item and role.
       
    76  *
       
    77  * \param index The index of the item to return data about.
       
    78  * \param role The data should be relevant to this particular purpose.
       
    79  * \return QVariant The data for the specified index and role.
       
    80  */
       
    81 QVariant MobHistoryModel::data(const QModelIndex& index, int role) const
       
    82 {
       
    83     // Invalid index
       
    84     if (!index.isValid())
       
    85         return QVariant();
       
    86     
       
    87     int row = index.row();
       
    88     
       
    89     // check that row and column are Ok
       
    90     if (!validRowId(row))
       
    91         return QVariant();
       
    92     
       
    93     switch(role)
       
    94     {
       
    95         case Qt::DisplayRole:
       
    96             return displayRoleData(row);
       
    97         case Qt::DecorationRole:
       
    98             return decorationRoleData(row);
       
    99         case SeenStatusRole:
       
   100             return seenStatusRoleData(row);
       
   101         case DirectionRole:
       
   102             return directionRoleData(row);
       
   103         default:
       
   104             return QVariant();
       
   105     }
       
   106 }
       
   107 
       
   108 /*!
       
   109  * Get the number of rows (conversations) in this model.
       
   110  *
       
   111  * \param parent Optional parent index value.
       
   112  * \return Number of rows in this model.
       
   113  */
       
   114 int MobHistoryModel::rowCount(const QModelIndex& /*parent*/) const
       
   115 {
       
   116     return d->m_table.size();
       
   117 }
       
   118 
       
   119 /*!
       
   120  * Sort list items on the model.
       
   121  *
       
   122  * \param column Column to be sorted. It is not used.
       
   123  * \param order Order to sort the list items.
       
   124  */
       
   125 void MobHistoryModel::sort(int /*column*/, Qt::SortOrder order)
       
   126 {
       
   127     if (order == Qt::AscendingOrder)
       
   128         qStableSort(d->m_table.begin(), d->m_table.end(), lessThan);
       
   129     else
       
   130         qStableSort(d->m_table.begin(), d->m_table.end(), greaterThan);
       
   131 }
       
   132 
       
   133 /*!
       
   134  * Clear all history from the database. If the history cached
       
   135  * is specific to one contact, only that history is cleared.
       
   136  * 
       
   137  */
       
   138 void MobHistoryModel::clearHistory()
       
   139 {
       
   140 
       
   141 }
       
   142 
       
   143 /*!
       
   144  * Create the model structure and cache history data from
       
   145  * conversations and call logs databases.
       
   146  *
       
   147  */
       
   148 void MobHistoryModel::initializeModel()
       
   149 {
       
   150     //populate model with call events
       
   151     d->m_logsModel = new LogsModel(LogsModel::LogsFullModel);
       
   152     if (!d->m_isMyCard) {
       
   153         //do the filtering to get call events for the target contact
       
   154         d->m_logsFilter = new LogsCustomFilter;
       
   155         d->m_logsFilter->setContactId(d->m_contactId);
       
   156         d->m_logsFilter->setSourceModel(d->m_logsModel);
       
   157         d->m_AbstractLogsModel = d->m_logsFilter;
       
   158     } else {
       
   159         //get all call events
       
   160         d->m_AbstractLogsModel = d->m_logsModel;
       
   161     }
       
   162     
       
   163     //read first call events and start listening for more 
       
   164     readEvents(0, d->m_AbstractLogsModel->rowCount());
       
   165     connect(d->m_AbstractLogsModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), 
       
   166             this, SLOT(dataFromLogsModel(const QModelIndex &, int, int)));
       
   167     
       
   168     // Messages database
       
   169     QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
       
   170     db.setDatabaseName("c:\\private\\20024328\\conversations.db");
       
   171     if (!db.isOpen())
       
   172         db.open();
       
   173     
       
   174     // All messages history model
       
   175     if (d->m_isMyCard) {
       
   176         d->m_conversationsModel = ConversationsModel::instance();
       
   177         // Connect to the MessageModel's signal
       
   178         connect(d->m_conversationsModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
       
   179                 this, SLOT(dataFromConversationsModel(const QModelIndex&, int, int)));
       
   180         //d->m_conversationsModel->refreshModel();
       
   181         
       
   182     // Person-centric messages history model
       
   183     } else {
       
   184         d->m_messageModel = MessageModel::instance();
       
   185         // Connect to the MessageModel's signal
       
   186         connect(d->m_messageModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
       
   187                 this, SLOT(dataFromMessageModel(const QModelIndex&, int, int)));
       
   188         d->m_messageModel->fetchMessages(d->m_contactId);
       
   189     }
       
   190 }
       
   191 
       
   192 /*!
       
   193  * Return the data to be used by the view for a display role.
       
   194  *
       
   195  * \param column The column of the item to return data about.
       
   196  *  return QVariant List of strings to be displayed on the view.
       
   197  *  The stings can also be NULL
       
   198  *  index 0 Title of the conversation item.
       
   199  *  index 1 Body text
       
   200  *  index 2 Time stamp
       
   201  */
       
   202 QVariant MobHistoryModel::displayRoleData(int row) const
       
   203 {
       
   204     TableRow tableRow = d->m_table.at(row);
       
   205     QStringList list;
       
   206     
       
   207     // Title
       
   208     QString title = tableRow.title;
       
   209     
       
   210     // Message
       
   211     QString msg = tableRow.message;
       
   212     
       
   213     // Time stamp string
       
   214     QString time = tableRow.timeStamp.toString();
       
   215     
       
   216     list << title << msg << time;
       
   217     
       
   218     return QVariant(list);
       
   219 }
       
   220 
       
   221 /*!
       
   222  * Return the data to be used by the view for a decoration role.
       
   223  *
       
   224  * \param row The row of the item to return data about.
       
   225  * \param column The column of the item to return data about.
       
   226  *  return QVariant Path of the icon
       
   227  */
       
   228 QVariant MobHistoryModel::decorationRoleData(int row) const
       
   229 {
       
   230     TableRow tableRow = d->m_table.at(row);
       
   231     return QVariant(tableRow.brandedIconPath);
       
   232 }
       
   233 
       
   234 /*!
       
   235  * Return the data to be used by the view for a seen status role.
       
   236  *
       
   237  * \param row The row of the item to return data about.
       
   238  * \param column The column of the item to return data about.
       
   239  *  return QVariant The status data for the specified index.
       
   240  */
       
   241 QVariant MobHistoryModel::seenStatusRoleData(int row) const
       
   242 {
       
   243     TableRow tableRow = d->m_table.at(row);
       
   244     return QVariant(tableRow.seenStatus);
       
   245 }
       
   246 
       
   247 /*!
       
   248  * Return the data to be used by the view for a direction role.
       
   249  *
       
   250  * \param row The row of the item to return data about.
       
   251  * \param column The column of the item to return data about.
       
   252  *  return QVariant The direction data for the specified index.
       
   253  */
       
   254 QVariant MobHistoryModel::directionRoleData(int row) const
       
   255 {
       
   256     TableRow tableRow = d->m_table.at(row);
       
   257     return QVariant(tableRow.direction);
       
   258 }
       
   259 
       
   260 /*!
       
   261  * Verify specified row id is valid.
       
   262  *
       
   263  * \param row A row number
       
   264  * \return bool indicating validity of row id
       
   265  */
       
   266 bool MobHistoryModel::validRowId(int row) const
       
   267 {
       
   268     return (row >= 0 && row < rowCount());
       
   269 }
       
   270 
       
   271 /*!
       
   272  * Adds call events to the combined (calls + messages) model
       
   273  *
       
   274  * \param first First new row in call's model
       
   275  * \param last Last new row in call's model
       
   276  */
       
   277 void MobHistoryModel::readEvents(int first, int last)
       
   278 {
       
   279     for (int i = first; i < d->m_AbstractLogsModel->rowCount() && i <= last; ++i) {
       
   280         LogsEvent* event = qVariantValue<LogsEvent*>(
       
   281                 d->m_AbstractLogsModel->data(d->m_AbstractLogsModel->index(i, 0), LogsModel::RoleFullEvent) );
       
   282         
       
   283         if (event) {
       
   284             TableRow row;
       
   285             QString bodyText;
       
   286             QString title;
       
   287             if (d->m_isMyCard) {
       
   288                 if (event->remoteParty().length() > 0) {
       
   289                     title = event->remoteParty();
       
   290                 }
       
   291                 else {
       
   292                     title = event->number();
       
   293                 }
       
   294             }
       
   295             else {
       
   296                 if (event->direction() == LogsEvent::DirIn) {
       
   297                     bodyText = QString("Incoming call");
       
   298                 } else if (event->direction() == LogsEvent::DirOut) {
       
   299                     bodyText = QString("Outgoing call");
       
   300                 } else if (event->direction() == LogsEvent::DirMissed) {
       
   301                     bodyText = QString("Missed call");
       
   302                     //if (!event->isRead())
       
   303                     //    row.seen_status = Unseen;
       
   304                 }
       
   305             }
       
   306 
       
   307             row.direction = Incoming;
       
   308             if (event->direction() == LogsEvent::DirOut) {
       
   309                 row.direction = Outgoing;
       
   310             }
       
   311             row.message = bodyText;
       
   312             row.title = title;
       
   313             row.timeStamp = event->time();
       
   314             
       
   315             QList<QVariant> icons = d->m_AbstractLogsModel->index(i, 0).data(Qt::DecorationRole).toList();
       
   316             if (!icons.isEmpty()) {
       
   317                 row.brandedIconPath = qVariantValue<HbIcon>(icons.at(0)).iconName();
       
   318             }
       
   319             
       
   320             d->m_table.append(row);
       
   321         }
       
   322     }
       
   323     sort();
       
   324 }
       
   325 
       
   326 /*!
       
   327  * Slot used for receiving new rows from the MessageModel.
       
   328  *
       
   329  * \param parent Optional parent index value.
       
   330  * \param first The first row item to be received from the model.
       
   331  * \param last The last row item to be received from the model.
       
   332  */
       
   333 void MobHistoryModel::dataFromMessageModel(const QModelIndex& /*parent*/, int first, int last)
       
   334 {
       
   335     // Add conversation items received
       
   336     int oldRowCount = rowCount();
       
   337     
       
   338     for(int i = first; i<last; i++) {
       
   339         QModelIndex index = d->m_messageModel->index(i, 1); // column value not used in msg model
       
   340         
       
   341         // Create and populate a new row to add to table from the messages model
       
   342         TableRow row;
       
   343         
       
   344         row.timeStamp.setTime_t(d->m_messageModel->data(index, TimeStamp).toInt());
       
   345         
       
   346         row.message = d->m_messageModel->data(index, BodyText).toString();
       
   347         if (d->m_isMyCard)
       
   348             row.message.prepend("Me: ");
       
   349         
       
   350         if (d->m_messageModel->data(index, Direction).toInt() == 0)
       
   351             row.direction = Incoming;
       
   352         else
       
   353             row.direction = Outgoing;
       
   354         
       
   355         if (d->m_messageModel->data(index, UnReadStatus).toBool())
       
   356             row.seenStatus = Unseen;
       
   357         else
       
   358             row.seenStatus = Seen;
       
   359         
       
   360         // Insert the row to our data model table
       
   361         d->m_table.append(row);
       
   362     }
       
   363     sort();
       
   364     
       
   365     // The items are sorted base on time. All new items added to the table
       
   366     // will end up at the end of the list.
       
   367     beginInsertRows(QModelIndex(), oldRowCount, rowCount());
       
   368     endInsertRows();
       
   369 }
       
   370 
       
   371 /*!
       
   372  * Slot used for receiving new rows from the ConversationModel.
       
   373  *
       
   374  * \param parent Optional parent index value.
       
   375  * \param first The first row item to be received from the model.
       
   376  * \param last The last row item to be received from the model.
       
   377  */
       
   378 void MobHistoryModel::dataFromConversationsModel(const QModelIndex& /*parent*/, int first, int last)
       
   379 {
       
   380     // Add conversation items received
       
   381     int oldRowCount = rowCount();
       
   382     
       
   383     for(int i = first; i<last; i++) {
       
   384         QModelIndex index = d->m_conversationsModel->index(i, 1); // column value not used in msg model
       
   385         
       
   386         // Create and populate a new row to add to table from the messages model
       
   387         TableRow row;
       
   388         
       
   389         row.title = d->m_conversationsModel->data(index, FirstName).toString();
       
   390         row.title.append(" ");
       
   391         row.title.append(d->m_conversationsModel->data(index, LastName).toString());
       
   392         
       
   393         row.timeStamp.setTime_t(d->m_conversationsModel->data(index, TimeStamp).toInt());
       
   394         row.message = d->m_conversationsModel->data(index, BodyText).toString();
       
   395         
       
   396         if (d->m_conversationsModel->data(index, Direction).toInt() == 0)
       
   397             row.direction = Incoming;
       
   398         else
       
   399             row.direction = Outgoing;
       
   400         
       
   401         if (d->m_conversationsModel->data(index, UnReadStatus).toBool())
       
   402             row.seenStatus = Unseen;
       
   403         else
       
   404             row.seenStatus = Seen;
       
   405         
       
   406         // Insert the row to our data model table.
       
   407         d->m_table.append(row);
       
   408     }
       
   409     sort();
       
   410 
       
   411     // The items are sorted base on time. All new items added to the table
       
   412     // will end up at the end of the list.
       
   413     beginInsertRows(QModelIndex(), oldRowCount, rowCount());
       
   414     endInsertRows();
       
   415 }
       
   416 
       
   417 /*!
       
   418  * Slot used for receiving new rows from the LogsModel.
       
   419  *
       
   420  * \param parent Optional parent index value.
       
   421  * \param first The first row item to be received from the model.
       
   422  * \param last The last row item to be received from the model.
       
   423  */
       
   424 void MobHistoryModel::dataFromLogsModel(const QModelIndex& /*parent*/, int first, int last)
       
   425 {
       
   426     int oldRowCount = rowCount();
       
   427     readEvents(first, last);
       
   428     beginInsertRows(QModelIndex(), oldRowCount, rowCount());
       
   429     endInsertRows();
       
   430 }