From f26e5e937520a93069a26edabd95386e38e0023f Mon Sep 17 00:00:00 2001
From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>
Date: Mon, 16 Dec 2013 12:12:40 -0500
Subject: [PATCH] [ #36988 ] Fix a race condition when changing the number of
 PhoneNumbers

---
 src/contact.cpp           |  7 ++++++-
 src/contact.h             |  2 ++
 src/contactproxymodel.cpp | 27 ++++++++++++++++++++++++++-
 src/contactproxymodel.h   |  4 +++-
 4 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/src/contact.cpp b/src/contact.cpp
index 96d544d3..3bc1ecd1 100644
--- a/src/contact.cpp
+++ b/src/contact.cpp
@@ -121,14 +121,19 @@ const QString& Contact::department() const
    return m_Department;
 }
 
-///Set the phone number (type and number) 
+///Set the phone number (type and number)
 void Contact::setPhoneNumbers(PhoneNumbers numbers)
 {
+   const int oldCount(m_Numbers.size()),newCount(numbers.size());
    foreach(PhoneNumber* n, m_Numbers)
       disconnect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged()));
    m_Numbers = numbers;
+   if (newCount < oldCount) //Rows need to be removed from models first
+      emit phoneNumberCountAboutToChange(newCount,oldCount);
    foreach(PhoneNumber* n, m_Numbers)
       connect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged()));
+   if (newCount > oldCount) //Need to be updated after the data to prevent invalid memory access
+      emit phoneNumberCountChanged(newCount,oldCount);
    emit changed();
 }
 
diff --git a/src/contact.h b/src/contact.h
index 8e6a4118..5ad75034 100644
--- a/src/contact.h
+++ b/src/contact.h
@@ -133,6 +133,8 @@ Q_SIGNALS:
    void presenceChanged( PhoneNumber* );
    void statusChanged  ( bool         );
    void changed        (              );
+   void phoneNumberCountChanged(int,int);
+   void phoneNumberCountAboutToChange(int,int);
 
 protected:
    //Presence secret methods
diff --git a/src/contactproxymodel.cpp b/src/contactproxymodel.cpp
index b96f4de6..d7a44fa0 100644
--- a/src/contactproxymodel.cpp
+++ b/src/contactproxymodel.cpp
@@ -94,6 +94,8 @@ ContactTreeBinder::ContactTreeBinder(ContactProxyModel* m,ContactTreeNode* n) :
    QObject(),m_pTreeNode(n),m_pModel(m)
 {
    connect(n->m_pContact,SIGNAL(changed()),this,SLOT(slotContactChanged()));
+   connect(n->m_pContact,SIGNAL(phoneNumberCountChanged(int,int)),this,SLOT(slotPhoneNumberCountChanged(int,int)));
+   connect(n->m_pContact,SIGNAL(phoneNumberCountAboutToChange(int,int)),this,SLOT(slotPhoneNumberCountAboutToChange(int,int)));
 }
 
 
@@ -101,7 +103,9 @@ void ContactTreeBinder::slotContactChanged()
 {
    const QModelIndex idx = m_pModel->index(m_pTreeNode->m_Index,0,m_pModel->index(m_pTreeNode->m_pParent3->m_Index,0));
    const QModelIndex lastPhoneIdx = m_pModel->index(m_pTreeNode->m_pContact->phoneNumbers().size()-1,0,idx);
-   emit m_pModel->dataChanged(idx,lastPhoneIdx);
+   emit m_pModel->dataChanged(idx,idx);
+   if (lastPhoneIdx.isValid()) //Need to be done twice
+      emit m_pModel->dataChanged(m_pModel->index(0,0,idx),lastPhoneIdx);
 }
 
 void ContactTreeBinder::slotStatusChanged()
@@ -109,6 +113,27 @@ void ContactTreeBinder::slotStatusChanged()
    
 }
 
+void ContactTreeBinder::slotPhoneNumberCountChanged(int count, int oldCount)
+{
+   const QModelIndex idx = m_pModel->index(m_pTreeNode->m_Index,0,m_pModel->index(m_pTreeNode->m_pParent3->m_Index,0));
+   if (count > oldCount) {
+      const QModelIndex lastPhoneIdx = m_pModel->index(oldCount-1,0,idx);
+      m_pModel->beginInsertRows(idx,oldCount,count-1);
+      m_pModel->endInsertRows();
+   }
+   emit m_pModel->dataChanged(idx,idx);
+}
+
+void ContactTreeBinder::slotPhoneNumberCountAboutToChange(int count, int oldCount)
+{
+   const QModelIndex idx = m_pModel->index(m_pTreeNode->m_Index,0,m_pModel->index(m_pTreeNode->m_pParent3->m_Index,0));
+   if (count < oldCount) {
+      //If count == 1, disable all children
+      m_pModel->beginRemoveRows(idx,count == 1?0:count,oldCount-1);
+      m_pModel->endRemoveRows();
+   }
+}
+
 //
 ContactProxyModel::ContactProxyModel(AbstractContactBackend* parent,int role, bool showAll) : QAbstractItemModel(QCoreApplication::instance()),
 m_pModel(parent),m_Role(role),m_ShowAll(showAll),m_lCategoryCounter()
diff --git a/src/contactproxymodel.h b/src/contactproxymodel.h
index f9454c43..a655a7db 100644
--- a/src/contactproxymodel.h
+++ b/src/contactproxymodel.h
@@ -85,7 +85,7 @@ private Q_SLOTS:
    void slotContactAdded(Contact* c);
 };
 
-class ContactTreeBinder : public QObject {
+class ContactTreeBinder : public QObject { //FIXME Qt5 remove when dropping Qt4
    Q_OBJECT
 public:
    ContactTreeBinder(ContactProxyModel* m,ContactTreeNode* n);
@@ -95,6 +95,8 @@ private:
 private Q_SLOTS:
    void slotContactChanged();
    void slotStatusChanged();
+   void slotPhoneNumberCountChanged(int,int);
+   void slotPhoneNumberCountAboutToChange(int,int);
 };
 
 #endif
-- 
GitLab