From 50ad86f78fb2ca2bcae61422094845bca4f9fede Mon Sep 17 00:00:00 2001
From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>
Date: Fri, 20 Mar 2015 12:50:42 -0400
Subject: [PATCH] codec: Port to selectionModel(), fix d&d, move code

Account::{reload,save}{Codec,Credential} are now moved to
CodecModel and CredentialModel

Refs #68848
---
 src/account.cpp         |  95 ++++++----------------------
 src/account.h           |   9 +--
 src/codecmodel.cpp      | 137 ++++++++++++++++++++++++++++------------
 src/codecmodel.h        |  48 ++++++++------
 src/credentialmodel.cpp |  62 +++++++++++++++++-
 src/credentialmodel.h   |  19 +++---
 src/mime.h              |   4 +-
 7 files changed, 216 insertions(+), 158 deletions(-)

diff --git a/src/account.cpp b/src/account.cpp
index d00972bf..4a55934b 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -340,18 +340,20 @@ QVariant Account::stateColor() const
 }
 
 ///Create and return the credential model
-CredentialModel* Account::credentialsModel() const
+CredentialModel* Account::credentialModel() const
 {
-   if (!d_ptr->m_pCredentials)
-      const_cast<Account*>(this)->reloadCredentials();
+   if (!d_ptr->m_pCredentials) {
+      d_ptr->m_pCredentials = new CredentialModel(const_cast<Account*>(this));
+   }
    return d_ptr->m_pCredentials;
 }
 
 ///Create and return the audio codec model
 CodecModel* Account::codecModel() const
 {
-   if (!d_ptr->m_pCodecModel)
-      const_cast<Account*>(this)->reloadCodecs();
+   if (!d_ptr->m_pCodecModel) {
+      d_ptr->m_pCodecModel = new CodecModel(const_cast<Account*>(this));
+   }
    return d_ptr->m_pCodecModel;
 }
 
@@ -471,8 +473,8 @@ QString Account::password() const
 {
    switch (protocol()) {
       case Account::Protocol::SIP:
-         if (credentialsModel()->rowCount())
-            return credentialsModel()->data(credentialsModel()->index(0,0),CredentialModel::Role::PASSWORD).toString();
+         if (credentialModel()->rowCount())
+            return credentialModel()->data(credentialModel()->index(0,0),CredentialModel::Role::PASSWORD).toString();
          break;
       case Account::Protocol::IAX:
          return d_ptr->accountDetail(DRing::Account::ConfProperties::PASSWORD);
@@ -1046,11 +1048,11 @@ void Account::setPassword(const QString& detail)
 {
    switch (protocol()) {
       case Account::Protocol::SIP:
-         if (credentialsModel()->rowCount())
-            credentialsModel()->setData(credentialsModel()->index(0,0),detail,CredentialModel::Role::PASSWORD);
+         if (credentialModel()->rowCount())
+            credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::PASSWORD);
          else {
-            const QModelIndex idx = credentialsModel()->addCredentials();
-            credentialsModel()->setData(idx,detail,CredentialModel::Role::PASSWORD);
+            const QModelIndex idx = credentialModel()->addCredentials();
+            credentialModel()->setData(idx,detail,CredentialModel::Role::PASSWORD);
          }
          break;
       case Account::Protocol::IAX:
@@ -1636,10 +1638,10 @@ void AccountPrivate::save()
          m_pCodecModel->setData(idx,QString::number(aCodec)  ,CodecModel::Role::ID         );
          m_pCodecModel->setData(idx, Qt::Checked ,Qt::CheckStateRole);
       }
-      q_ptr->saveCodecs();
+      q_ptr->codecModel()->save();
 
       q_ptr->setId(currentId.toLatin1());
-      q_ptr->saveCredentials();
+      q_ptr->credentialModel()->save();
    } //New account
    else { //Existing account
       MapStringString tmp;
@@ -1664,7 +1666,8 @@ void AccountPrivate::save()
       m_CurrentState = Account::EditState::READY;
    }
 
-   q_ptr->saveCodecs();
+   q_ptr->codecModel()->save();
+
    emit q_ptr->changed(q_ptr);
 }
 
@@ -1709,7 +1712,7 @@ void AccountPrivate::reload()
 
       //If the credential model is loaded, then update it
       if (m_pCredentials)
-         q_ptr->reloadCredentials();
+         m_pCredentials->reload();
       emit q_ptr->changed(q_ptr);
 
       //The registration state is cached, update that cache
@@ -1744,53 +1747,6 @@ void AccountPrivate::outdate() {
    changeState(Account::EditState::OUTDATED);
 }
 
-
-///Reload credentials from DBUS
-void Account::reloadCredentials()
-{
-   if (!d_ptr->m_pCredentials) {
-      d_ptr->m_pCredentials = new CredentialModel(this);
-   }
-   if (!isNew()) {
-      d_ptr->m_pCredentials->clear();
-      ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
-      VectorMapStringString credentials = configurationManager.getCredentials(id());
-      for (int i=0; i < credentials.size(); i++) {
-         QModelIndex idx = d_ptr->m_pCredentials->addCredentials();
-         d_ptr->m_pCredentials->setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME    );
-         d_ptr->m_pCredentials->setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD);
-         d_ptr->m_pCredentials->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM    ],CredentialModel::Role::REALM   );
-      }
-   }
-}
-
-///Save all credentials
-void Account::saveCredentials() {
-   if (d_ptr->m_pCredentials) {
-      ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
-      VectorMapStringString toReturn;
-      for (int i=0; i < d_ptr->m_pCredentials->rowCount();i++) {
-         QModelIndex idx = d_ptr->m_pCredentials->index(i,0);
-         MapStringString credentialData;
-         QString user = d_ptr->m_pCredentials->data(idx,CredentialModel::Role::NAME).toString();
-         QString realm = d_ptr->m_pCredentials->data(idx,CredentialModel::Role::REALM).toString();
-         if (user.isEmpty()) {
-            user = username();
-            d_ptr->m_pCredentials->setData(idx,user,CredentialModel::Role::NAME);
-         }
-         if (realm.isEmpty()) {
-            realm = '*';
-            d_ptr->m_pCredentials->setData(idx,realm,CredentialModel::Role::REALM);
-         }
-         credentialData[ DRing::Account::ConfProperties::USERNAME ] = user;
-         credentialData[ DRing::Account::ConfProperties::PASSWORD ] = d_ptr->m_pCredentials->data(idx,CredentialModel::Role::PASSWORD).toString();
-         credentialData[ DRing::Account::ConfProperties::REALM    ] = realm;
-         toReturn << credentialData;
-      }
-      configurationManager.setCredentials(id(),toReturn);
-   }
-}
-
 void AccountPrivate::regenSecurityValidation()
 {
    if (m_pSecurityValidationModel) {
@@ -1801,21 +1757,6 @@ void AccountPrivate::regenSecurityValidation()
    }
 }
 
-///Reload all audio codecs
-void Account::reloadCodecs()
-{
-   if (!d_ptr->m_pCodecModel) {
-      d_ptr->m_pCodecModel = new CodecModel(this);
-   }
-   d_ptr->m_pCodecModel->reload();
-}
-
-///Save audio codecs
-void Account::saveCodecs() {
-   if (d_ptr->m_pCodecModel)
-      d_ptr->m_pCodecModel->save();
-}
-
 /*****************************************************************************
  *                                                                           *
  *                                 Operator                                  *
diff --git a/src/account.h b/src/account.h
index 998a9687..929a3826 100644
--- a/src/account.h
+++ b/src/account.h
@@ -246,7 +246,7 @@ class LIB_EXPORT Account : public QObject {
       QVariant         stateColor      () const;
       virtual bool     isLoaded        () const;
 
-      Q_INVOKABLE CredentialModel*         credentialsModel       () const;
+      Q_INVOKABLE CredentialModel*         credentialModel        () const;
       Q_INVOKABLE CodecModel*              codecModel             () const;
       Q_INVOKABLE RingToneModel*           ringToneModel          () const;
       Q_INVOKABLE KeyExchangeModel*        keyExchangeModel       () const;
@@ -381,13 +381,6 @@ class LIB_EXPORT Account : public QObject {
       bool operator==(const Account&)const;
       Account* operator<<(Account::EditAction& action);
 
-      //Mutator
-      Q_INVOKABLE void saveCredentials  ();
-      Q_INVOKABLE void saveCodecs       ();
-      Q_INVOKABLE void reloadCredentials();
-      Q_INVOKABLE void reloadCodecs     ();
-
-
    public Q_SLOTS:
       void setEnabled(bool checked);
 
diff --git a/src/codecmodel.cpp b/src/codecmodel.cpp
index dcc2bed4..9dfa182c 100644
--- a/src/codecmodel.cpp
+++ b/src/codecmodel.cpp
@@ -21,6 +21,7 @@
 #include <QtCore/QDebug>
 #include <QtCore/QCoreApplication>
 #include <QtCore/QSortFilterProxyModel>
+#include <QtCore/QItemSelectionModel>
 #include <QMimeData>
 
 //DRing
@@ -47,22 +48,24 @@ public:
    };
 
    //Attributes
-   QList<CodecData*>      m_lCodecs  ;
-   QMap<int,bool>         m_lEnabledCodecs;
-   Account*               m_pAccount      ;
-   QSortFilterProxyModel* m_pAudioProxy   ;
-   QSortFilterProxyModel* m_pVideoProxy   ;
-   QStringList            m_lMimes        ;
+   QList<CodecData*>      m_lCodecs        ;
+   QMap<int,bool>         m_lEnabledCodecs ;
+   Account*               m_pAccount       ;
+   QSortFilterProxyModel* m_pAudioProxy    ;
+   QSortFilterProxyModel* m_pVideoProxy    ;
+   QStringList            m_lMimes         ;
+   QItemSelectionModel*   m_pSelectionModel;
 
    //Helpers
    bool findCodec(int id);
+   QModelIndex getIndexofCodecByID(int id);
 
 private:
    CodecModel* q_ptr;
 };
 
 CodecModelPrivate::CodecModelPrivate(CodecModel* parent) : q_ptr(parent),
-m_pAudioProxy(nullptr),m_pVideoProxy(nullptr)
+m_pAudioProxy(nullptr),m_pVideoProxy(nullptr),m_pSelectionModel(nullptr)
 {
 
 }
@@ -74,6 +77,7 @@ QAbstractListModel(account?(QObject*)account:(QObject*)QCoreApplication::instanc
    d_ptr->m_pAccount = account;
    setObjectName("CodecModel: "+(account?account->id():"Unknown"));
    d_ptr->m_lMimes << RingMimes::AUDIO_CODEC << RingMimes::VIDEO_CODEC;
+   reload();
 }
 
 CodecModel::~CodecModel()
@@ -100,8 +104,16 @@ QHash<int,QByteArray> CodecModel::roleNames() const
    return roles;
 }
 
+QItemSelectionModel* CodecModel::selectionModel() const
+{
+   if (!d_ptr->m_pSelectionModel)
+      d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<CodecModel*>(this));
+   return d_ptr->m_pSelectionModel;
+}
+
 ///Model data
-QVariant CodecModel::data(const QModelIndex& idx, int role) const {
+QVariant CodecModel::data(const QModelIndex& idx, int role) const
+{
    if(idx.column() == 0      && role == Qt::DisplayRole                   ) {
       return QVariant(d_ptr->m_lCodecs[idx.row()]->name);
    }
@@ -127,13 +139,15 @@ QVariant CodecModel::data(const QModelIndex& idx, int role) const {
 }
 
 ///Number of audio codecs
-int CodecModel::rowCount(const QModelIndex& par) const {
+int CodecModel::rowCount(const QModelIndex& par) const
+{
    Q_UNUSED(par)
    return d_ptr->m_lCodecs.size();
 }
 
 ///Model flags
-Qt::ItemFlags CodecModel::flags(const QModelIndex& idx) const {
+Qt::ItemFlags CodecModel::flags(const QModelIndex& idx) const
+{
    if (idx.column() == 0)
       return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable
                                             | Qt::ItemIsEnabled
@@ -144,7 +158,8 @@ Qt::ItemFlags CodecModel::flags(const QModelIndex& idx) const {
 }
 
 ///Set audio codec data
-bool CodecModel::setData( const QModelIndex& idx, const QVariant &value, int role) {
+bool CodecModel::setData( const QModelIndex& idx, const QVariant &value, int role)
+{
    if (idx.column() == 0 && role == CodecModel::NAME) {
       d_ptr->m_lCodecs[idx.row()]->name = value.toString();
       emit dataChanged(idx, idx);
@@ -178,6 +193,16 @@ bool CodecModel::setData( const QModelIndex& idx, const QVariant &value, int rol
    return false;
 }
 
+Qt::DropActions CodecModel::supportedDragActions() const
+{
+   return Qt::MoveAction | Qt::TargetMoveAction;
+}
+
+Qt::DropActions CodecModel::supportedDropActions() const
+{
+   return Qt::MoveAction | Qt::TargetMoveAction;
+}
+
 ///Add a new audio codec
 QModelIndex CodecModel::add() {
    d_ptr->m_lCodecs << new CodecModelPrivate::CodecData;
@@ -265,6 +290,32 @@ void CodecModel::save()
    configurationManager.setActiveCodecList(d_ptr->m_pAccount->id(), _codecList);
 }
 
+///Move a codec up in the priority list (using the selectionModel)
+bool CodecModel::moveUp()
+{
+   if (d_ptr->m_pSelectionModel) {
+      const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex();
+      if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()-1, idx.column(),idx.parent())) {
+         d_ptr->m_pSelectionModel->setCurrentIndex(index(idx.row()-1,idx.column()), QItemSelectionModel::ClearAndSelect);
+         return true;
+      }
+   }
+   return false;
+}
+
+///Move a codec down in the priority list (using the selectionModel)
+bool CodecModel::moveDown()
+{
+   if (d_ptr->m_pSelectionModel) {
+      const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex();
+      if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()+1, idx.column(),idx.parent())) {
+         d_ptr->m_pSelectionModel->setCurrentIndex(index(idx.row()+1,idx.column()), QItemSelectionModel::ClearAndSelect);
+         return true;
+      }
+   }
+   return false;
+}
+
 ///Check is a codec is already in the list
 bool CodecModelPrivate::findCodec(int id)
 {
@@ -278,39 +329,38 @@ bool CodecModelPrivate::findCodec(int id)
 
 QSortFilterProxyModel* CodecModel::audioCodecs() const
 {
-    if (!d_ptr->m_pAudioProxy) {
-        d_ptr->m_pAudioProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
-        d_ptr->m_pAudioProxy->setSourceModel(const_cast<CodecModel*>(this));
-        d_ptr->m_pAudioProxy->setFilterRole(CodecModel::Role::TYPE);
-        d_ptr->m_pAudioProxy->setFilterFixedString("AUDIO");
-    }
-    return d_ptr->m_pAudioProxy;
+   if (!d_ptr->m_pAudioProxy) {
+      d_ptr->m_pAudioProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
+      d_ptr->m_pAudioProxy->setSourceModel(const_cast<CodecModel*>(this));
+      d_ptr->m_pAudioProxy->setFilterRole(CodecModel::Role::TYPE);
+      d_ptr->m_pAudioProxy->setFilterFixedString("AUDIO");
+   }
+   return d_ptr->m_pAudioProxy;
 }
 
 QSortFilterProxyModel* CodecModel::videoCodecs() const
 {
-    if (!d_ptr->m_pVideoProxy) {
-        d_ptr->m_pVideoProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
-        d_ptr->m_pVideoProxy->setSourceModel(const_cast<CodecModel*>(this));
-        d_ptr->m_pVideoProxy->setFilterRole(CodecModel::Role::TYPE);
-        d_ptr->m_pVideoProxy->setFilterFixedString("VIDEO");
-    }
-    return d_ptr->m_pVideoProxy;
+   if (!d_ptr->m_pVideoProxy) {
+      d_ptr->m_pVideoProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
+      d_ptr->m_pVideoProxy->setSourceModel(const_cast<CodecModel*>(this));
+      d_ptr->m_pVideoProxy->setFilterRole(CodecModel::Role::TYPE);
+      d_ptr->m_pVideoProxy->setFilterFixedString("VIDEO");
+   }
+   return d_ptr->m_pVideoProxy;
 }
 
-QModelIndex CodecModel::getIndexofCodecByID(int id)
+// ======== DnD Api =========
+
+QModelIndex CodecModelPrivate::getIndexofCodecByID(int id)
 {
-    for (int i=0; i < rowCount();i++) {
-       const QModelIndex& idx = index(i,0);
-       if (data(idx, CodecModel::Role::ID) == id) {
-          return idx;
-       }
-    }
-    return QModelIndex();
+   for (int i=0; i < q_ptr->rowCount();i++) {
+      const QModelIndex& idx = q_ptr->index(i,0);
+      if (q_ptr->data(idx, CodecModel::Role::ID) == id)
+         return idx;
+   }
+   return QModelIndex();
 }
 
-// ======== DnD Api =========
-
 ///Return valid payload types
 int CodecModel::acceptedPayloadTypes() const
 {
@@ -340,7 +390,7 @@ bool CodecModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int
       else if(row >= d_ptr->m_lCodecs.size()) {
          destinationRow = 0;
       }
-      else if(data->hasFormat(RingMimes::VIDEO_CODEC) && row >= d_ptr->m_pVideoProxy->rowCount()) {
+      else if(data->hasFormat(RingMimes::VIDEO_CODEC) && row >= rowCount()) {
          destinationRow = 0;
       }
       else {
@@ -350,7 +400,8 @@ bool CodecModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int
       const int codecId = data->data(data->hasFormat(RingMimes::AUDIO_CODEC)
                                                     ? RingMimes::AUDIO_CODEC
                                                     : RingMimes::VIDEO_CODEC).toInt();
-      const QModelIndex codecIdx = getIndexofCodecByID(codecId);
+
+      const QModelIndex codecIdx = d_ptr->getIndexofCodecByID(codecId);
 
       beginRemoveRows(QModelIndex(), codecIdx.row(), codecIdx.row());
       CodecModelPrivate::CodecData* codecInfo = d_ptr->m_lCodecs[codecIdx.row()];
@@ -373,15 +424,17 @@ QMimeData* CodecModel::mimeData(const QModelIndexList& indexes) const
 
    for (const QModelIndex& index : indexes) {
       if (index.isValid()) {
-         if(index.data(CodecModel::Role::TYPE).toString() == "AUDIO")
-            mMimeData->setData(RingMimes::AUDIO_CODEC , index.data(CodecModel::Role::ID).toByteArray());
-         else
-            mMimeData->setData(RingMimes::VIDEO_CODEC , index.data(CodecModel::Role::ID).toByteArray());
+         qDebug() << "setting mime data for row: " << index.row();
+
+         const QByteArray mime = (index.data(CodecModel::Role::TYPE).toString() == "AUDIO")
+            ? RingMimes::AUDIO_CODEC
+            : RingMimes::VIDEO_CODEC;
 
+         mMimeData->setData(mime, index.data(CodecModel::Role::ID).toByteArray());
       }
    }
+
    return mMimeData;
 }
 
-
 #include <codecmodel.moc>
diff --git a/src/codecmodel.h b/src/codecmodel.h
index 798748ae..2c818858 100644
--- a/src/codecmodel.h
+++ b/src/codecmodel.h
@@ -23,6 +23,7 @@
 //Qt
 #include <QtCore/QString>
 class QSortFilterProxyModel;
+class QItemSelectionModel;
 
 //Ring
 #include <typedefs.h>
@@ -37,10 +38,11 @@ class LIB_EXPORT CodecModel : public QAbstractListModel {
    Q_OBJECT
    #pragma GCC diagnostic pop
 
+   //Only Account:: can create this type
    friend class Account;
 
 public:
-   //friend class Account;
+
    //Roles
    enum Role {
       ID         = 103,
@@ -50,29 +52,39 @@ public:
       TYPE       = 104,
    };
 
+   //Properties
+   Q_PROPERTY(QSortFilterProxyModel* audioCodecs    READ audioCodecs    )
+   Q_PROPERTY(QSortFilterProxyModel* videoCodecs    READ videoCodecs    )
+   Q_PROPERTY(QItemSelectionModel*   selectionModel READ selectionModel )
+
    //Abstract model member
-   virtual QVariant data        (const QModelIndex& index, int role = Qt::DisplayRole      ) const override;
-   virtual int rowCount         (const QModelIndex& parent = QModelIndex()                 ) const override;
-   virtual Qt::ItemFlags flags  (const QModelIndex& index                                  ) const override;
-   virtual bool setData         (const QModelIndex& index, const QVariant &value, int role )       override;
-   virtual QHash<int,QByteArray> roleNames() const override;
+   virtual QVariant              data        ( const QModelIndex& index, int role = Qt::DisplayRole      ) const override;
+   virtual int                   rowCount    ( const QModelIndex& parent = QModelIndex()                 ) const override;
+   virtual Qt::ItemFlags         flags       ( const QModelIndex& index                                  ) const override;
+   virtual bool                  setData     ( const QModelIndex& index, const QVariant &value, int role )       override;
+   virtual QHash<int,QByteArray> roleNames   (                                                           ) const override;
+   virtual QMimeData*            mimeData    ( const QModelIndexList &indexes                            ) const override;
+   virtual QStringList           mimeTypes   (                                                           ) const override;
+   virtual bool                  dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override;
+   virtual Qt::DropActions       supportedDragActions() const override;
+   virtual Qt::DropActions       supportedDropActions() const override;
 
    //Proxies
    QSortFilterProxyModel* audioCodecs() const;
    QSortFilterProxyModel* videoCodecs() const;
 
-   //Mutator
-   QModelIndex add();
-   Q_INVOKABLE void    remove      ( const QModelIndex& idx         );
-   virtual QMimeData*  mimeData    ( const QModelIndexList &indexes ) const override;
-   virtual bool        dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
-   virtual QStringList mimeTypes   (                                ) const override;
-   Q_INVOKABLE void    clear       (                                );
-   Q_INVOKABLE void    reload      (                                );
-   Q_INVOKABLE void    save        (                                );
-
-   int acceptedPayloadTypes() const;
-   QModelIndex getIndexofCodecByID(int id);
+   //Getter
+   int                  acceptedPayloadTypes() const;
+   QItemSelectionModel* selectionModel      () const;
+
+public Q_SLOTS:
+   QModelIndex add         (                        );
+   void        remove      ( const QModelIndex& idx );
+   void        clear       (                        );
+   void        reload      (                        );
+   void        save        (                        );
+   bool        moveUp      (                        );
+   bool        moveDown    (                        );
 
 private:
 
diff --git a/src/credentialmodel.cpp b/src/credentialmodel.cpp
index 07bbdebd..b65a3ae8 100644
--- a/src/credentialmodel.cpp
+++ b/src/credentialmodel.cpp
@@ -17,9 +17,17 @@
  ***************************************************************************/
 #include "credentialmodel.h"
 
+//Qt
 #include <QtCore/QDebug>
 #include <QtCore/QCoreApplication>
 
+//Ring
+#include <account.h>
+
+//Dring
+#include "dbus/configurationmanager.h"
+#include <account_const.h>
+
 class CredentialModelPrivate
 {
 public:
@@ -32,13 +40,17 @@ public:
 
    //Attributes
    QList<CredentialData2*> m_lCredentials;
+   Account*                m_pAccount;
 };
 
 ///Constructor
-CredentialModel::CredentialModel(QObject* par) : QAbstractListModel(par?par:QCoreApplication::instance()),
+CredentialModel::CredentialModel(Account* acc) : QAbstractListModel(acc),
 d_ptr(new CredentialModelPrivate())
 {
+   Q_ASSERT(acc);
+   d_ptr->m_pAccount = acc;
    QHash<int, QByteArray> roles = roleNames();
+   reload();
 }
 
 CredentialModel::~CredentialModel()
@@ -123,7 +135,8 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in
 }
 
 ///Add a new credential
-QModelIndex CredentialModel::addCredentials() {
+QModelIndex CredentialModel::addCredentials()
+{
    beginInsertRows(QModelIndex(), d_ptr->m_lCredentials.size()-1, d_ptr->m_lCredentials.size()-1);
    d_ptr->m_lCredentials << new CredentialModelPrivate::CredentialData2;
    endInsertRows();
@@ -132,7 +145,8 @@ QModelIndex CredentialModel::addCredentials() {
 }
 
 ///Remove credential at 'idx'
-void CredentialModel::removeCredentials(QModelIndex idx) {
+void CredentialModel::removeCredentials(const QModelIndex& idx)
+{
    if (idx.isValid()) {
       beginRemoveRows(QModelIndex(), idx.row(), idx.row());
       d_ptr->m_lCredentials.removeAt(idx.row());
@@ -152,3 +166,45 @@ void CredentialModel::clear()
    }
    d_ptr->m_lCredentials.clear();
 }
+
+///Save all credentials
+void CredentialModel::save()
+{
+   ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
+   VectorMapStringString toReturn;
+   for (int i=0; i < rowCount();i++) {
+      const QModelIndex& idx = index(i,0);
+      MapStringString credentialData;
+      QString user  = data(idx,CredentialModel::Role::NAME).toString();
+      QString realm = data(idx,CredentialModel::Role::REALM).toString();
+      if (user.isEmpty()) {
+         user = d_ptr->m_pAccount->username();
+         setData(idx,user,CredentialModel::Role::NAME);
+      }
+      if (realm.isEmpty()) {
+         realm = '*';
+         setData(idx,realm,CredentialModel::Role::REALM);
+      }
+      credentialData[ DRing::Account::ConfProperties::USERNAME ] = user;
+      credentialData[ DRing::Account::ConfProperties::PASSWORD ] = data(idx,CredentialModel::Role::PASSWORD).toString();
+      credentialData[ DRing::Account::ConfProperties::REALM    ] = realm;
+      toReturn << credentialData;
+   }
+   configurationManager.setCredentials(d_ptr->m_pAccount->id(),toReturn);
+}
+
+///Reload credentials from DBUS
+void CredentialModel::reload()
+{
+   if (!d_ptr->m_pAccount->isNew()) {
+      clear();
+      ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
+      const VectorMapStringString credentials = configurationManager.getCredentials(d_ptr->m_pAccount->id());
+      for (int i=0; i < credentials.size(); i++) {
+         const QModelIndex& idx = addCredentials();
+         setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME    );
+         setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD);
+         setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM    ],CredentialModel::Role::REALM   );
+      }
+   }
+}
diff --git a/src/credentialmodel.h b/src/credentialmodel.h
index b208af43..8e655d76 100644
--- a/src/credentialmodel.h
+++ b/src/credentialmodel.h
@@ -24,6 +24,7 @@
 
 
 class CredentialModelPrivate;
+class Account;
 
 ///CredentialModel: A model for account credentials
 class LIB_EXPORT CredentialModel : public QAbstractListModel {
@@ -40,20 +41,22 @@ public:
    };
 
    //Constructor
-   explicit CredentialModel(QObject* parent = nullptr);
+   explicit CredentialModel(Account* acc);
    virtual ~CredentialModel();
 
    //Abstract model member
-   QVariant data(const QModelIndex& index, int role = Qt::DisplayRole ) const override;
-   int rowCount(const QModelIndex& parent = QModelIndex()             ) const override;
-   Qt::ItemFlags flags(const QModelIndex& index                       ) const override;
-   virtual bool setData(const QModelIndex& index, const QVariant &value, int role) override;
-   virtual QHash<int,QByteArray> roleNames() const override;
+   QVariant                      data     ( const QModelIndex& index, int role = Qt::DisplayRole     ) const override;
+   int                           rowCount ( const QModelIndex& parent = QModelIndex()                ) const override;
+   Qt::ItemFlags                 flags    ( const QModelIndex& index                                 ) const override;
+   virtual bool                  setData  ( const QModelIndex& index, const QVariant &value, int role)       override;
+   virtual QHash<int,QByteArray> roleNames(                                                          ) const override;
 
    //Mutator
    QModelIndex addCredentials();
-   void removeCredentials(QModelIndex idx);
-   void clear();
+   void removeCredentials(const QModelIndex& idx);
+   void clear ();
+   void save  ();
+   void reload();
 
 private:
    QScopedPointer<CredentialModelPrivate> d_ptr;
diff --git a/src/mime.h b/src/mime.h
index 5b222e37..e0b2e40a 100644
--- a/src/mime.h
+++ b/src/mime.h
@@ -27,8 +27,8 @@ namespace RingMimes {
    constexpr static const char* HTML_TEXT   = "text/html"               ;
    constexpr static const char* PROFILE     = "text/ring.profile.id"    ;
    constexpr static const char* ACCOUNT     = "text/sflphone.account.id";
-   constexpr static const char* AUDIO_CODEC = "text/ring.codec.audio";
-   constexpr static const char* VIDEO_CODEC = "text/ring.codec.video";
+   constexpr static const char* AUDIO_CODEC = "text/ring.codec.audio"   ;
+   constexpr static const char* VIDEO_CODEC = "text/ring.codec.video"   ;
 }
 
 #endif
-- 
GitLab