Skip to content
Snippets Groups Projects
Commit fda661ff authored by Emmanuel Lepage Vallee's avatar Emmanuel Lepage Vallee Committed by gerrit2
Browse files

credential: Re-write the credentialmodel as a tree

The CredentialModel was previously only used for SIP credential. This
commit extend it so it can handle multiple types of Credentials

**WARNING** Introduce a minor API change. CredentialModel::addCredential()
now take a Credential::Type as argument. This will be mitigated by the
next commit that introduce a credential creation model.

Issue: #78102
Change-Id: Id7e1fc9391784ff654dfdfbb812c581fbfa8fd1e
parent d91dfb00
Branches
Tags
No related merge requests found
...@@ -1393,7 +1393,7 @@ void Account::setUsername(const QString& detail) ...@@ -1393,7 +1393,7 @@ void Account::setUsername(const QString& detail)
if (credentialModel()->rowCount()) if (credentialModel()->rowCount())
credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::NAME); credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::NAME);
else { else {
const QModelIndex idx = credentialModel()->addCredentials(); const QModelIndex idx = credentialModel()->addCredentials(Credential::Type::SIP);
credentialModel()->setData(idx,detail,CredentialModel::Role::NAME); credentialModel()->setData(idx,detail,CredentialModel::Role::NAME);
} }
break; break;
...@@ -1420,7 +1420,7 @@ void Account::setPassword(const QString& detail) ...@@ -1420,7 +1420,7 @@ void Account::setPassword(const QString& detail)
if (credentialModel()->rowCount()) if (credentialModel()->rowCount())
credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::PASSWORD); credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::PASSWORD);
else { else {
const QModelIndex idx = credentialModel()->addCredentials(); const QModelIndex idx = credentialModel()->addCredentials(Credential::Type::SIP);
credentialModel()->setData(idx,detail,CredentialModel::Role::PASSWORD); credentialModel()->setData(idx,detail,CredentialModel::Role::PASSWORD);
} }
break; break;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
//Ring //Ring
#include <account.h> #include <account.h>
#include <credential.h>
#include <private/matrixutils.h> #include <private/matrixutils.h>
//Dring //Dring
...@@ -32,16 +31,43 @@ ...@@ -32,16 +31,43 @@
typedef void (CredentialModelPrivate::*CredModelFct)(); typedef void (CredentialModelPrivate::*CredModelFct)();
struct CredentialNode final
{
union {
struct {
Credential* m_pCredential = {nullptr};
CredentialNode* m_pParent = {nullptr};
} m_Cred;
struct {
QString* m_CategoryName = {nullptr};
QVector<CredentialNode*>* m_lChildren;
} m_Category;
} m_uContent;
enum class Level {
CATEGORY,
CREDENTIAL
};
short int m_Index = {-1};
Level m_Level;
};
void free_node(CredentialNode* n);
class CredentialModelPrivate class CredentialModelPrivate
{ {
public: public:
//Attributes //Attributes
QList<Credential*> m_lCredentials; QList<CredentialNode*> m_lCategories ;
Account* m_pAccount ; Account* m_pAccount ;
CredentialModel::EditState m_EditState ; CredentialModel::EditState m_EditState ;
CredentialModel* q_ptr ; CredentialModel* q_ptr ;
uint m_TopLevelCount = {3};
static Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> m_mStateMachine; static Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> m_mStateMachine;
CredentialNode* m_pSipCat = {nullptr};
CredentialNode* m_pTurnCat = {nullptr};
CredentialNode* m_pStunCat = {nullptr};
//Callbacks //Callbacks
void clear (); void clear ();
...@@ -52,20 +78,22 @@ public: ...@@ -52,20 +78,22 @@ public:
//Helper //Helper
inline void performAction(const CredentialModel::EditAction action); inline void performAction(const CredentialModel::EditAction action);
CredentialNode* getCategory(Credential::Type type);
CredentialNode* createCat(const QString& name);
}; };
#define CMP &CredentialModelPrivate #define CMP &CredentialModelPrivate
Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> CredentialModelPrivate::m_mStateMachine ={{ Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> CredentialModelPrivate::m_mStateMachine ={{
/* SAVE MODIFY RELOAD CLEAR */ /* SAVE MODIFY RELOAD CLEAR */
/* LOADING */ {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }}, { CredentialModel::EditState::LOADING , {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }}},
/* READY */ {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }}, { CredentialModel::EditState::READY , {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }}},
/* MODIFIED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}, { CredentialModel::EditState::MODIFIED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}},
/* OUTDATED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}, { CredentialModel::EditState::OUTDATED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}},
}}; }};
#undef CMP #undef CMP
///Constructor ///Constructor
CredentialModel::CredentialModel(Account* acc) : QAbstractListModel(acc), CredentialModel::CredentialModel(Account* acc) : QAbstractItemModel(acc),
d_ptr(new CredentialModelPrivate()) d_ptr(new CredentialModelPrivate())
{ {
Q_ASSERT(acc); Q_ASSERT(acc);
...@@ -79,8 +107,8 @@ d_ptr(new CredentialModelPrivate()) ...@@ -79,8 +107,8 @@ d_ptr(new CredentialModelPrivate())
CredentialModel::~CredentialModel() CredentialModel::~CredentialModel()
{ {
foreach (Credential* data, d_ptr->m_lCredentials) { foreach (CredentialNode* data, d_ptr->m_lCategories) {
delete data; free(data); //delete doesn't support non-trivial structures
} }
} }
...@@ -97,61 +125,138 @@ QHash<int,QByteArray> CredentialModel::roleNames() const ...@@ -97,61 +125,138 @@ QHash<int,QByteArray> CredentialModel::roleNames() const
return roles; return roles;
} }
///Get the parent index
QModelIndex CredentialModel::parent( const QModelIndex& index) const
{
if (!index.isValid())
return QModelIndex();
const CredentialNode* node = static_cast<CredentialNode*>(index.internalPointer());
if ((!node) || node->m_Level == CredentialNode::Level::CATEGORY)
return QModelIndex();
return createIndex(node->m_uContent.m_Cred.m_pParent->m_Index,0,node->m_uContent.m_Cred.m_pParent);
}
///Get the column count
int CredentialModel::columnCount( const QModelIndex& parent) const
{
Q_UNUSED(parent)
return 1;
}
///Create the indexes
QModelIndex CredentialModel::index( int row, int column, const QModelIndex& parent) const
{
if (column)
return QModelIndex();
if (parent.isValid()) {
const CredentialNode* node = static_cast<CredentialNode*>(parent.internalPointer());
if (node->m_Level != CredentialNode::Level::CATEGORY
|| row >= node->m_uContent.m_Category.m_lChildren->size())
return QModelIndex();
return createIndex(row, column, node->m_uContent.m_Category.m_lChildren->at(row));
}
if (row >= d_ptr->m_lCategories.size())
return QModelIndex();
return createIndex(row, column, d_ptr->m_lCategories[row]);
}
///Model data ///Model data
QVariant CredentialModel::data(const QModelIndex& idx, int role) const { QVariant CredentialModel::data(const QModelIndex& idx, int role) const {
if (!idx.isValid()) if (!idx.isValid())
return QVariant(); return QVariant();
if (idx.column() == 0) { const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer());
switch (role) {
case Qt::DisplayRole: switch (node->m_Level) {
return QVariant(d_ptr->m_lCredentials[idx.row()]->username()); case CredentialNode::Level::CATEGORY:
case CredentialModel::Role::NAME: switch(role) {
return d_ptr->m_lCredentials[idx.row()]->username(); case Qt::DisplayRole:
case CredentialModel::Role::PASSWORD: return *node->m_uContent.m_Category.m_CategoryName;
return d_ptr->m_lCredentials[idx.row()]->password(); }
case CredentialModel::Role::REALM: break;
return d_ptr->m_lCredentials[idx.row()]->realm(); case CredentialNode::Level::CREDENTIAL:
default: switch (role) {
break; case Qt::DisplayRole:
} case CredentialModel::Role::NAME:
return node->m_uContent.m_Cred.m_pCredential->username();
case CredentialModel::Role::PASSWORD:
return node->m_uContent.m_Cred.m_pCredential->password();
case CredentialModel::Role::REALM:
return node->m_uContent.m_Cred.m_pCredential->realm();
default:
break;
}
break;
} }
return QVariant(); return QVariant();
} }
///Number of credentials ///Number of credentials
int CredentialModel::rowCount(const QModelIndex& par) const { int CredentialModel::rowCount(const QModelIndex& par) const {
Q_UNUSED(par) if (!par.isValid())
return d_ptr->m_lCredentials.size(); return d_ptr->m_lCategories.size();
const CredentialNode* node = static_cast<CredentialNode*>(par.internalPointer());
if (node->m_Level == CredentialNode::Level::CREDENTIAL)
return 0;
return d_ptr->m_lCategories[par.row()]->m_uContent.m_Category.m_lChildren->size();
} }
///Model flags ///Model flags
Qt::ItemFlags CredentialModel::flags(const QModelIndex& idx) const { Qt::ItemFlags CredentialModel::flags(const QModelIndex& idx) const {
if (idx.column() == 0) if (!idx.isValid())
return QAbstractItemModel::flags(idx) /*| Qt::ItemIsUserCheckable*/ | Qt::ItemIsEnabled | Qt::ItemIsSelectable; return Qt::NoItemFlags;
return QAbstractItemModel::flags(idx);
const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer());
//Categories cannot be selected
switch (node->m_Level) {
case CredentialNode::Level::CATEGORY:
return Qt::ItemIsEnabled;
case CredentialNode::Level::CREDENTIAL:
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
//TODO make turn/stun disabled is account doesn't support/disable it
}
return Qt::NoItemFlags;
} }
///Set credential data ///Set credential data
bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, int role) { bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, int role) {
if (!idx.isValid() || idx.row() > d_ptr->m_lCredentials.size()-1) if (!idx.isValid())
return false; return false;
const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer());
if (node->m_Level == CredentialNode::Level::CATEGORY)
return false;
if (idx.column() == 0 && role == CredentialModel::Role::NAME) { if (idx.column() == 0 && role == CredentialModel::Role::NAME) {
d_ptr->m_lCredentials[idx.row()]->setUsername(value.toString()); node->m_uContent.m_Cred.m_pCredential->setUsername(value.toString());
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY; this << EditAction::MODIFY;
return true; return true;
} }
else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) { else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) {
if (d_ptr->m_lCredentials[idx.row()]->password() != value.toString()) { if (node->m_uContent.m_Cred.m_pCredential->password() != value.toString()) {
d_ptr->m_lCredentials[idx.row()]->setPassword(value.toString()); node->m_uContent.m_Cred.m_pCredential->setPassword(value.toString());
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY; this << EditAction::MODIFY;
return true; return true;
} }
} }
else if (idx.column() == 0 && role == CredentialModel::Role::REALM) { else if (idx.column() == 0 && role == CredentialModel::Role::REALM) {
d_ptr->m_lCredentials[idx.row()]->setRealm(value.toString()); node->m_uContent.m_Cred.m_pCredential->setRealm(value.toString());
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
this << EditAction::MODIFY; this << EditAction::MODIFY;
return true; return true;
...@@ -159,27 +264,92 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in ...@@ -159,27 +264,92 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in
return false; return false;
} }
CredentialNode* CredentialModelPrivate::createCat(const QString& name)
{
CredentialNode* n = (CredentialNode*) malloc(sizeof(CredentialNode));
n->m_Level = CredentialNode::Level::CATEGORY;
n->m_Index = q_ptr->rowCount();
n->m_uContent.m_Category.m_CategoryName = new QString(name);
n->m_uContent.m_Category.m_lChildren = new QVector<CredentialNode*>();
q_ptr->beginInsertRows(QModelIndex(),m_lCategories.size(),0);
m_lCategories << n;
q_ptr->endInsertRows();
return n;
}
void free_node(CredentialNode* n)
{
switch (n->m_Level) {
case CredentialNode::Level::CATEGORY:
delete n->m_uContent.m_Category.m_CategoryName;
delete n->m_uContent.m_Category.m_lChildren;
break;
case CredentialNode::Level::CREDENTIAL:
delete n->m_uContent.m_Cred.m_pCredential;
break;
}
free(n);
}
CredentialNode* CredentialModelPrivate::getCategory(Credential::Type type)
{
switch (type) {
case Credential::Type::SIP:
if (!m_pSipCat)
m_pSipCat = createCat(QStringLiteral("SIP"));
return m_pSipCat;
case Credential::Type::TURN:
if (!m_pTurnCat)
m_pTurnCat = createCat(QStringLiteral("TURN"));
return m_pTurnCat;
case Credential::Type::STUN:
if (m_pStunCat)
m_pStunCat = createCat(QStringLiteral("STUN"));
return m_pStunCat;
}
return nullptr;
}
///Add a new credential ///Add a new credential
QModelIndex CredentialModel::addCredentials() QModelIndex CredentialModel::addCredentials(Credential::Type type)
{ {
beginInsertRows(QModelIndex(), d_ptr->m_lCredentials.size()-1, d_ptr->m_lCredentials.size()-1); CredentialNode* par = d_ptr->getCategory(type);
d_ptr->m_lCredentials << new Credential(Credential::Type::SIP); const int count = par->m_uContent.m_Category.m_lChildren->size();
const QModelIndex parIdx = index(par->m_Index,0);
beginInsertRows(parIdx, count, count);
CredentialNode* node = (CredentialNode*) malloc(sizeof(CredentialNode));
node->m_Level = CredentialNode::Level::CREDENTIAL;
node->m_uContent.m_Cred.m_pCredential = new Credential(type);
node->m_uContent.m_Cred.m_pParent = par;
node->m_Index = par->m_uContent.m_Category.m_lChildren->size();
par->m_uContent.m_Category.m_lChildren->append(node);
endInsertRows(); endInsertRows();
emit dataChanged(index(d_ptr->m_lCredentials.size()-1,0), index(d_ptr->m_lCredentials.size()-1,0));
this << EditAction::MODIFY; this << EditAction::MODIFY;
return index(d_ptr->m_lCredentials.size()-1,0);
return index(count, 0, parIdx);
} }
///Remove credential at 'idx' ///Remove credential at 'idx'
void CredentialModel::removeCredentials(const QModelIndex& idx) void CredentialModel::removeCredentials(const QModelIndex& idx)
{ {
if (idx.isValid()) { if (idx.isValid() && idx.parent().isValid()) {
beginRemoveRows(QModelIndex(), idx.row(), idx.row()); beginRemoveRows(idx.parent(), idx.row(), idx.row());
Credential* d = d_ptr->m_lCredentials[idx.row()];
d_ptr->m_lCredentials.removeAt(idx.row()); CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer());
delete d;
for (int i = node->m_Index+1; i < node->m_uContent.m_Cred.m_pParent->m_uContent.m_Category.m_lChildren->size();i++) {
node->m_uContent.m_Cred.m_pParent->m_uContent.m_Category.m_lChildren->at(i)->m_Index--;
}
node->m_uContent.m_Cred.m_pParent->m_uContent.m_Category.m_lChildren->removeAt(node->m_Index);
free_node(node);
endRemoveRows(); endRemoveRows();
emit dataChanged(idx, index(d_ptr->m_lCredentials.size()-1,0));
this << EditAction::MODIFY; this << EditAction::MODIFY;
} }
else { else {
...@@ -190,10 +360,12 @@ void CredentialModel::removeCredentials(const QModelIndex& idx) ...@@ -190,10 +360,12 @@ void CredentialModel::removeCredentials(const QModelIndex& idx)
///Remove everything ///Remove everything
void CredentialModelPrivate::clear() void CredentialModelPrivate::clear()
{ {
foreach(Credential* data2, m_lCredentials) { q_ptr->beginRemoveRows(QModelIndex(),0,q_ptr->rowCount());
delete data2; foreach(CredentialNode* data2, m_lCategories) {
free_node(data2);
} }
m_lCredentials.clear(); m_lCategories.clear();
q_ptr->endRemoveRows();
m_EditState = CredentialModel::EditState::READY; m_EditState = CredentialModel::EditState::READY;
} }
...@@ -233,7 +405,7 @@ void CredentialModelPrivate::reload() ...@@ -233,7 +405,7 @@ void CredentialModelPrivate::reload()
ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance();
const VectorMapStringString credentials = configurationManager.getCredentials(m_pAccount->id()); const VectorMapStringString credentials = configurationManager.getCredentials(m_pAccount->id());
for (int i=0; i < credentials.size(); i++) { for (int i=0; i < credentials.size(); i++) {
const QModelIndex& idx = q_ptr->addCredentials(); const QModelIndex& idx = q_ptr->addCredentials(Credential::Type::SIP);
q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME ); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME );
q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD);
q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM ); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM );
...@@ -255,7 +427,7 @@ void CredentialModelPrivate::modify() ...@@ -255,7 +427,7 @@ void CredentialModelPrivate::modify()
void CredentialModelPrivate::performAction(const CredentialModel::EditAction action) void CredentialModelPrivate::performAction(const CredentialModel::EditAction action)
{ {
(this->*(m_mStateMachine[m_EditState][action]))();//FIXME don't use integer cast (this->*(m_mStateMachine[m_EditState][action]))();
} }
/// anAccount << Call::EditAction::SAVE /// anAccount << Call::EditAction::SAVE
......
...@@ -17,16 +17,21 @@ ...@@ -17,16 +17,21 @@
***************************************************************************/ ***************************************************************************/
#pragma once #pragma once
#include <QtCore/QString>
#include <QtCore/QAbstractListModel> #include <QtCore/QAbstractListModel>
#include "typedefs.h" #include "typedefs.h"
//Qt
#include <QtCore/QString>
//Ring
#include <credential.h>
class CredentialModelPrivate; class CredentialModelPrivate;
class Account; class Account;
///CredentialModel: A model for account credentials ///CredentialModel: A model for account credentials
class LIB_EXPORT CredentialModel : public QAbstractListModel { class LIB_EXPORT CredentialModel : public QAbstractItemModel {
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
Q_OBJECT Q_OBJECT
...@@ -62,14 +67,17 @@ public: ...@@ -62,14 +67,17 @@ public:
virtual ~CredentialModel(); virtual ~CredentialModel();
//Abstract model member //Abstract model member
QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override;
Qt::ItemFlags flags ( const QModelIndex& index ) const override; virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override;
virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override;
virtual QHash<int,QByteArray> roleNames( ) const override; virtual QModelIndex parent ( const QModelIndex& index ) const override;
virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override;
virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override;
virtual QHash<int,QByteArray> roleNames( ) const override;
//Mutator //Mutator
QModelIndex addCredentials(); QModelIndex addCredentials(Credential::Type type);
void removeCredentials(const QModelIndex& idx); void removeCredentials(const QModelIndex& idx);
bool performAction(CredentialModel::EditAction action); bool performAction(CredentialModel::EditAction action);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment