From 1b178b25ada269b89704a4dcc771f7a6f50c9286 Mon Sep 17 00:00:00 2001
From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>
Date: Mon, 9 Mar 2015 13:49:46 -0400
Subject: [PATCH] collection: Port the collection model to the new API

Refs #68098
---
 CMakeLists.txt                     |   2 +
 src/backendmanagerinterface.hpp    | 105 -------------------------
 src/collectionmanagerinterface.cpp |  33 ++++++++
 src/collectionmanagerinterface.h   |  26 ++++++-
 src/collectionmanagerinterface.hpp |   4 +
 src/collectionmodel.cpp            | 120 +++++++++++++++--------------
 src/collectionmodel.h              |   8 +-
 src/private/collectionmodel_p.h    |  65 ++++++++++++++++
 8 files changed, 198 insertions(+), 165 deletions(-)
 delete mode 100644 src/backendmanagerinterface.hpp
 create mode 100644 src/collectionmanagerinterface.cpp
 create mode 100644 src/private/collectionmodel_p.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1906d59c..c974ab81 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -197,6 +197,7 @@ SET( libringclient_LIB_SRCS
   src/securityvalidationmodel.cpp
   src/personmodel.cpp
   src/collectionmodel.cpp
+  src/collectionmanagerinterface.cpp
   src/networkinterfacemodel.cpp
   src/certificatemodel.cpp
   src/ciphermodel.cpp
@@ -453,6 +454,7 @@ SET(libringclient_PRIVATE_HDRS
    src/private/phonedirectorymodel_p.h
    src/private/instantmessagingmodel_p.h
    src/private/videorenderer_p.h
+   src/private/collectionmodel_p.h
 )
 
 IF(${ENABLE_LIBWRAP} MATCHES true)
diff --git a/src/backendmanagerinterface.hpp b/src/backendmanagerinterface.hpp
deleted file mode 100644
index 7818eb7e..00000000
--- a/src/backendmanagerinterface.hpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/****************************************************************************
- *   Copyright (C) 2014-2015 by Savoir-Faire Linux                          *
- *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
- *                                                                          *
- *   This library is free software; you can redistribute it and/or          *
- *   modify it under the terms of the GNU Lesser General Public             *
- *   License as published by the Free Software Foundation; either           *
- *   version 2.1 of the License, or (at your option) any later version.     *
- *                                                                          *
- *   This library is distributed in the hope that it will be useful,        *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
- *   Lesser General Public License for more details.                        *
- *                                                                          *
- *   You should have received a copy of the GNU General Public License      *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
- ***************************************************************************/
-
-template <class T>
-class BackendManagerInterfacePrivate
-{
-public:
-   BackendManagerInterfacePrivate(BackendManagerInterface<T>* p) : m_pMediator(nullptr),q_ptr(p)
-   {}
-   ~BackendManagerInterfacePrivate();
-
-   QVector< CollectionInterface* > m_lBackends;
-   QVector< CollectionInterface* > m_lEnabledBackends;
-   mutable CollectionMediator<T>*  m_pMediator;
-   BackendManagerInterface<T>*      q_ptr;
-
-   CollectionMediator<T>* itemMediator() const;
-};
-
-template<class T>
-CollectionMediator<T>* BackendManagerInterfacePrivate<T>::itemMediator() const
-{
-   if (!m_pMediator) {
-      m_pMediator = new CollectionMediator<T>(q_ptr);
-   }
-   return m_pMediator;
-}
-
-template<class T>
-BackendManagerInterfacePrivate<T>::~BackendManagerInterfacePrivate()
-{
-   if (m_pMediator)
-      delete m_pMediator;
-}
-
-template<class T>
-template <class T2>
-CollectionInterface* BackendManagerInterface<T>::addBackend(const LoadOptions options)
-{
-   T2* backend = new T2(d_ptr->itemMediator());
-   d_ptr->m_lBackends << backend;
-
-   if (options & LoadOptions::FORCE_ENABLED) { //TODO check is the backend is checked
-
-      //Some collections can fail to load directly
-      //eventually it will necessary to add an async version of this
-      //to load the backend only when it is loaded
-      if (backend->load())
-         d_ptr->m_lEnabledBackends << backend;
-   }
-
-   return backend;
-}
-
-template<class T>
-BackendManagerInterface<T>::BackendManagerInterface() : d_ptr(new BackendManagerInterfacePrivate<T>(this))
-{
-
-}
-
-template<class T>
-const QVector< CollectionInterface* > BackendManagerInterface<T>::collections() const
-{
-   return d_ptr->m_lBackends;
-}
-
-template<class T>
-const QVector< CollectionInterface* > BackendManagerInterface<T>::enabledCollections() const
-{
-   return d_ptr->m_lEnabledBackends;
-}
-
-/// Do this manager have active collections
-template<class T>
-bool BackendManagerInterface<T>::hasEnabledCollections() const
-{
-   return d_ptr->m_lEnabledBackends.size();
-}
-
-template<class T>
-bool BackendManagerInterface<T>::hasCollections() const
-{
-   return d_ptr->m_lBackends.size();
-}
-
-template<class T>
-bool BackendManagerInterface<T>::clearAllCollections() const
-{
-   return false;
-}
diff --git a/src/collectionmanagerinterface.cpp b/src/collectionmanagerinterface.cpp
new file mode 100644
index 00000000..78782919
--- /dev/null
+++ b/src/collectionmanagerinterface.cpp
@@ -0,0 +1,33 @@
+/****************************************************************************
+ *   Copyright (C) 2014-2015 by Savoir-Faire Linux                          *
+ *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+#include "collectionmanagerinterface.h"
+
+//Ring
+#include <collectionmodel.h>
+#include "private/collectionmodel_p.h"
+
+class CollectionManagerInterfaceBasePrivate
+{
+public:
+
+};
+
+void CollectionManagerInterfaceBase::registerToModel(CollectionInterface* col) const
+{
+   CollectionModel::instance()->d_ptr->registerNew(col);
+}
\ No newline at end of file
diff --git a/src/collectionmanagerinterface.h b/src/collectionmanagerinterface.h
index 7ead6bc4..ab1e6b6b 100644
--- a/src/collectionmanagerinterface.h
+++ b/src/collectionmanagerinterface.h
@@ -30,7 +30,6 @@
 #include <collectioninterface.h>
 #include <collectionmediator.h>
 
-class CommonCollectionModel;
 class QAbstractItemModel;
 
 enum LoadOptions {
@@ -39,6 +38,29 @@ enum LoadOptions {
    FORCE_DISABLED = 0x1 << 1,
 };
 
+class CollectionManagerInterfaceBasePrivate;
+
+/**
+ * Common elements for each CollectionManagerInterface
+ */
+class CollectionManagerInterfaceBase {
+public:
+   virtual bool hasEnabledCollections (CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const = 0;
+   virtual bool hasCollections        (CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const = 0;
+
+   ///Enable / disable a collection
+   virtual bool enableBackend( CollectionInterface*  collection, bool enabled) = 0;
+
+   virtual bool clearAllCollections() const = 0;
+
+protected:
+   void registerToModel(CollectionInterface* col) const;
+
+private:
+   CollectionManagerInterfaceBasePrivate* d_ptr;
+   Q_DECLARE_PRIVATE(CollectionManagerInterfaceBase)
+};
+
 template <class T>
 class CollectionManagerInterfacePrivate;
 
@@ -65,7 +87,7 @@ class CollectionManagerInterfacePrivate;
  * implement the common logic that should otherwise have been copy pasted in each
  * collections.
  */
-template <class T> class LIB_EXPORT CollectionManagerInterface {
+template <class T> class LIB_EXPORT CollectionManagerInterface  : public CollectionManagerInterfaceBase {
    friend class CollectionMediator<T>;
 
 public:
diff --git a/src/collectionmanagerinterface.hpp b/src/collectionmanagerinterface.hpp
index d196fce8..c0f7c422 100644
--- a/src/collectionmanagerinterface.hpp
+++ b/src/collectionmanagerinterface.hpp
@@ -72,6 +72,8 @@ T2* CollectionManagerInterface<T>::addBackend(const LoadOptions options)
          d_ptr->m_lEnabledCollections << backend;
    }
 
+   registerToModel(backend);
+
    return backend;
 }
 #else
@@ -93,6 +95,8 @@ T2* CollectionManagerInterface<T>::addBackend(Ts... args, const LoadOptions opti
          d_ptr->m_lEnabledCollections << collection;
    }
 
+   registerToModel(collection);
+
    return collection;
 }
 #endif //Q_OS_DARWIN
diff --git a/src/collectionmodel.cpp b/src/collectionmodel.cpp
index 535b3af2..05e66d0a 100644
--- a/src/collectionmodel.cpp
+++ b/src/collectionmodel.cpp
@@ -17,40 +17,16 @@
  ***************************************************************************/
 #include "collectionmodel.h"
 
+//Qt
+#include <QtCore/QCoreApplication>
+
+//Ring
 #include "collectionmanagerinterface.h"
 #include "delegates/itemmodelstateserializationdelegate.h"
 #include "collectionextensioninterface.h"
+#include "private/collectionmodel_p.h"
 
-class CollectionModelPrivate : public QObject
-{
-   Q_OBJECT
-public:
-   CollectionModelPrivate(CollectionModel* parent);
-
-   /*
-    * This is not very efficient, it doesn't really have to be given the low
-    * volume. If it ever have to scale, a better mapToSource using persistent
-    * index have to be implemented.
-    */
-   struct ProxyItem {
-      ProxyItem() : parent(nullptr),col(1),row(0),backend(nullptr){}
-      int row;
-      int col;
-      CollectionInterface* backend;
-      ProxyItem* parent;
-      QVector<ProxyItem*> m_Children;
-   };
-   QHash<CollectionInterface**,ProxyItem*> m_hBackendsNodes;
-   QVector<ProxyItem*> m_lTopLevelBackends;
-   QVector<CollectionExtensionInterface*> m_lExtensions;
-
-private:
-   CollectionModel* q_ptr;
-
-private Q_SLOTS:
-   void slotUpdate();
-   void slotExtensionDataChanged(const QModelIndex& idx);
-};
+CollectionModel* CollectionModelPrivate::m_spInstance = nullptr;
 
 CollectionModelPrivate::CollectionModelPrivate(CollectionModel* parent) : QObject(parent),q_ptr(parent)
 {}
@@ -77,6 +53,13 @@ CollectionModel::~CollectionModel()
    }
 }
 
+CollectionModel* CollectionModel::instance()
+{
+   if (!CollectionModelPrivate::m_spInstance)
+      CollectionModelPrivate::m_spInstance = new CollectionModel(QCoreApplication::instance());
+   return CollectionModelPrivate::m_spInstance;
+}
+
 QHash<int,QByteArray> CollectionModel::roleNames() const
 {
    static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
@@ -94,20 +77,20 @@ QVariant CollectionModel::data (const QModelIndex& idx, int role) const
       CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer());
 
       if (idx.column() > 0)
-         return d_ptr->m_lExtensions[idx.column()-1]->data(item->backend,idx,role);
+         return d_ptr->m_lExtensions[idx.column()-1]->data(item->collection,idx,role);
 
       switch(role) {
          case Qt::DisplayRole:
-            return item->backend->name();
+            return item->collection->name();
             break;
          case Qt::DecorationRole:
-            return item->backend->icon();
+            return item->collection->icon();
             break;
 //          case Qt::CheckStateRole:
-//             return item->backend->isEnabled()?Qt::Checked:Qt::Unchecked;
+//             return item->collection->isEnabled()?Qt::Checked:Qt::Unchecked;
          case Qt::CheckStateRole: {
             if (ItemModelStateSerializationDelegate::instance())
-               return ItemModelStateSerializationDelegate::instance()->isChecked(item->backend)?Qt::Checked:Qt::Unchecked;
+               return ItemModelStateSerializationDelegate::instance()->isChecked(item->collection)?Qt::Checked:Qt::Unchecked;
          }
       };
    }
@@ -121,18 +104,11 @@ QVariant CollectionModel::data (const QModelIndex& idx, int role) const
 int CollectionModel::rowCount (const QModelIndex& parent) const
 {
    if (!parent.isValid()) {
-      static bool init = false; //FIXME this doesn't allow dynamic collections
-      static int result = 0;
-      if (!init) {
-         for(int i=0;i<PersonModel::instance()->collections().size();i++)
-            result += PersonModel::instance()->collections()[i]->parent()==nullptr?1:0;
-         init = true;
-      }
-      return result;
+      return d_ptr->m_lTopLevelBackends.size();
    }
    else {
       CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(parent.internalPointer());
-      return item->backend->children().size();
+      return item->collection->children().size();
    }
 }
 
@@ -149,10 +125,10 @@ Qt::ItemFlags CollectionModel::flags(const QModelIndex& idx) const
    CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer());
    if (idx.column() > 0) {
       //Make sure the cell is disabled if the row is
-      Qt::ItemFlags f = d_ptr->m_lExtensions[idx.column()-1]->flags(item->backend,idx);
-      return  (((f&Qt::ItemIsEnabled)&&(!item->backend->isEnabled()))?f^Qt::ItemIsEnabled:f);
+      Qt::ItemFlags f = d_ptr->m_lExtensions[idx.column()-1]->flags(item->collection,idx);
+      return  (((f&Qt::ItemIsEnabled)&&(!item->collection->isEnabled()))?f^Qt::ItemIsEnabled:f);
    }
-   const bool checkable = item->backend->supportedFeatures() & (CollectionInterface::SupportedFeatures::ENABLEABLE |
+   const bool checkable = item->collection->supportedFeatures() & (CollectionInterface::SupportedFeatures::ENABLEABLE |
    CollectionInterface::SupportedFeatures::DISABLEABLE | CollectionInterface::SupportedFeatures::MANAGEABLE  );
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | (checkable?Qt::ItemIsUserCheckable:Qt::NoItemFlags);
 }
@@ -164,14 +140,14 @@ bool CollectionModel::setData (const QModelIndex& idx, const QVariant &value, in
    Q_UNUSED(role)
    if (idx.isValid() && idx.column() > 0) {
       CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer());
-      return d_ptr->m_lExtensions[idx.column()-1]->setData(item->backend,idx,value,role);
+      return d_ptr->m_lExtensions[idx.column()-1]->setData(item->collection,idx,value,role);
    }
 
    if (role == Qt::CheckStateRole && idx.column() == 0) {
       CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer());
       if (item) {
-         const bool old = item->backend->isEnabled();
-         ItemModelStateSerializationDelegate::instance()->setChecked(item->backend,value==Qt::Checked);
+         const bool old = item->collection->isEnabled();
+         ItemModelStateSerializationDelegate::instance()->setChecked(item->collection,value==Qt::Checked);
          emit dataChanged(index(idx.row(),0),index(idx.row(),columnCount()-1));
          if (old != (value==Qt::Checked)) {
             emit checkStateChanged();
@@ -203,7 +179,7 @@ QModelIndex CollectionModel::index( int row, int column, const QModelIndex& pare
       else {
          item = new CollectionModelPrivate::ProxyItem();
          item->parent = parentItem;
-         item->backend = parentItem->backend->children()[row];
+         item->collection = parentItem->collection->children()[row];
          parentItem->m_Children << item;
       }
       item->row    = row;
@@ -220,7 +196,7 @@ QModelIndex CollectionModel::index( int row, int column, const QModelIndex& pare
             return QModelIndex();
 
          item = new CollectionModelPrivate::ProxyItem();
-         item->backend = PersonModel::instance()->collections()[row];
+         item->collection = PersonModel::instance()->collections()[row];
          d_ptr->m_lTopLevelBackends << item;
       }
       item->row = row;
@@ -251,7 +227,7 @@ bool CollectionModel::save()
 
       //Load newly enabled collections
       foreach(CollectionModelPrivate::ProxyItem* top, d_ptr->m_lTopLevelBackends) {
-         CollectionInterface* current = top->backend;
+         CollectionInterface* current = top->collection;
          bool check = ItemModelStateSerializationDelegate::instance()->isChecked(current);
          bool wasChecked = current->isEnabled();
          if (check && !wasChecked)
@@ -261,7 +237,7 @@ bool CollectionModel::save()
 
          //TODO implement real tree digging
          foreach(CollectionModelPrivate::ProxyItem* leaf ,top->m_Children) {
-            current = leaf->backend;
+            current = leaf->collection;
             check = ItemModelStateSerializationDelegate::instance()->isChecked(current);
             wasChecked = current->isEnabled();
             if (check && !wasChecked)
@@ -284,12 +260,12 @@ bool CollectionModel::load()
    return false;
 }
 
-///Return the backend at a given index
-CollectionInterface* CollectionModel::backendAt(const QModelIndex& index)
+///Return the collection at a given index
+CollectionInterface* CollectionModel::collectionAt(const QModelIndex& index)
 {
    if (!index.isValid())
       return nullptr;
-   return static_cast<CollectionModelPrivate::ProxyItem*>(index.internalPointer())->backend;
+   return static_cast<CollectionModelPrivate::ProxyItem*>(index.internalPointer())->collection;
 }
 
 void CollectionModel::addExtension(CollectionExtensionInterface* extension)
@@ -305,4 +281,34 @@ void CollectionModelPrivate::slotExtensionDataChanged(const QModelIndex& idx)
    emit q_ptr->dataChanged(idx,idx);
 }
 
+void CollectionModelPrivate::registerNew(CollectionInterface* col)
+{
+   if (!col)
+      return;
+
+   ProxyItem* item = new ProxyItem();
+   if (col->parent()) {
+      ProxyItem* p = m_hBackendsNodes[col->parent()];
+      item->parent = p;
+      item->row    = p->m_Children.size();
+      item->col    = 0;
+      q_ptr->beginInsertRows(q_ptr->createIndex(p->row,p->col,p),p->m_Children.size(),p->m_Children.size());
+      p->m_Children << item;
+      q_ptr->endInsertRows();
+   }
+   else {
+      item->parent = nullptr;
+      item->row    = m_lTopLevelBackends.size();
+      item->col    = 0;
+
+      q_ptr->beginInsertRows(QModelIndex(),m_lTopLevelBackends.size(),m_lTopLevelBackends.size());
+      m_lTopLevelBackends << item;
+      q_ptr->endInsertRows();
+   }
+
+
+   item->collection      = col ;
+   m_hBackendsNodes[col] = item;
+}
+
 #include <collectionmodel.moc>
diff --git a/src/collectionmodel.h b/src/collectionmodel.h
index aaec2659..3710ee63 100644
--- a/src/collectionmodel.h
+++ b/src/collectionmodel.h
@@ -31,10 +31,14 @@
 class CollectionExtensionInterface;
 
 class CollectionModelPrivate;
+class CollectionManagerInterfaceBase;
 
 class LIB_EXPORT CollectionModel : public QAbstractTableModel
 {
    Q_OBJECT
+
+   friend class CollectionManagerInterfaceBase;
+
 public:
    explicit CollectionModel(QObject* parent = nullptr);
    virtual ~CollectionModel();
@@ -49,13 +53,15 @@ public:
    virtual QModelIndex   index  ( int row, int column, const QModelIndex& parent=QModelIndex()) const override;
    virtual QHash<int,QByteArray> roleNames() const override;
 
-   CollectionInterface* backendAt(const QModelIndex& index);
+   CollectionInterface* collectionAt(const QModelIndex& index);
 
    void addExtension(CollectionExtensionInterface* extension);
 
    bool save();
    bool load();
 
+   static CollectionModel* instance();
+
 Q_SIGNALS:
    void checkStateChanged();
 
diff --git a/src/private/collectionmodel_p.h b/src/private/collectionmodel_p.h
new file mode 100644
index 00000000..5dff0d4d
--- /dev/null
+++ b/src/private/collectionmodel_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+ *   Copyright (C) 2014-2015 by Savoir-Faire Linux                          *
+ *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
+ *                                                                          *
+ *   This library is free software; you can redistribute it and/or          *
+ *   modify it under the terms of the GNU Lesser General Public             *
+ *   License as published by the Free Software Foundation; either           *
+ *   version 2.1 of the License, or (at your option) any later version.     *
+ *                                                                          *
+ *   This library is distributed in the hope that it will be useful,        *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
+ *   Lesser General Public License for more details.                        *
+ *                                                                          *
+ *   You should have received a copy of the GNU General Public License      *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+#ifndef COLLECTIONMODELPRIVATE_H
+#define COLLECTIONMODELPRIVATE_H
+
+#include <QtCore/QObject>
+#include <QtCore/QVector>
+#include <QtCore/QHash>
+
+class CollectionInterface;
+class CollectionModel;
+class CollectionExtensionInterface;
+
+class CollectionModelPrivate : public QObject
+{
+   Q_OBJECT
+public:
+   CollectionModelPrivate(CollectionModel* parent);
+
+   /*
+    * This is not very efficient, it doesn't really have to be given the low
+    * volume. If it ever have to scale, a better mapToSource using persistent
+    * index have to be implemented.
+    */
+   struct ProxyItem {
+      ProxyItem() : parent(nullptr),col(1),row(0),collection(nullptr){}
+      int row;
+      int col;
+      CollectionInterface* collection;
+      ProxyItem* parent;
+      QVector<ProxyItem*> m_Children;
+   };
+
+   QHash<CollectionInterface*,ProxyItem*> m_hBackendsNodes;
+   QVector<ProxyItem*>                    m_lTopLevelBackends;
+   QVector<CollectionExtensionInterface*> m_lExtensions;
+   static CollectionModel*                m_spInstance;
+
+   //Helper
+   void registerNew(CollectionInterface* col);
+
+private:
+   CollectionModel* q_ptr;
+
+private Q_SLOTS:
+   void slotUpdate();
+   void slotExtensionDataChanged(const QModelIndex& idx);
+};
+
+#endif
\ No newline at end of file
-- 
GitLab