diff --git a/src/account.cpp b/src/account.cpp index 895efc3ff37c2ecef6511cd436c01962f8faf595..8098a88115d66821f3eef0f57a413c2be79f7ab1 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -1393,7 +1393,7 @@ void Account::setUsername(const QString& detail) if (credentialModel()->rowCount()) credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::NAME); else { - const QModelIndex idx = credentialModel()->addCredentials(); + const QModelIndex idx = credentialModel()->addCredentials(Credential::Type::SIP); credentialModel()->setData(idx,detail,CredentialModel::Role::NAME); } break; @@ -1420,7 +1420,7 @@ void Account::setPassword(const QString& detail) if (credentialModel()->rowCount()) credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::PASSWORD); else { - const QModelIndex idx = credentialModel()->addCredentials(); + const QModelIndex idx = credentialModel()->addCredentials(Credential::Type::SIP); credentialModel()->setData(idx,detail,CredentialModel::Role::PASSWORD); } break; diff --git a/src/credentialmodel.cpp b/src/credentialmodel.cpp index a4abbda0e11cc32a77969c67073c31cfd28e7050..fac046a95ae4891d98f92ca40cf47e60d59d0aa0 100644 --- a/src/credentialmodel.cpp +++ b/src/credentialmodel.cpp @@ -23,7 +23,6 @@ //Ring #include <account.h> -#include <credential.h> #include <private/matrixutils.h> //Dring @@ -32,16 +31,43 @@ 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 { public: //Attributes - QList<Credential*> m_lCredentials; - Account* m_pAccount ; - CredentialModel::EditState m_EditState ; - CredentialModel* q_ptr ; + QList<CredentialNode*> m_lCategories ; + Account* m_pAccount ; + CredentialModel::EditState m_EditState ; + CredentialModel* q_ptr ; + uint m_TopLevelCount = {3}; static Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> m_mStateMachine; + CredentialNode* m_pSipCat = {nullptr}; + CredentialNode* m_pTurnCat = {nullptr}; + CredentialNode* m_pStunCat = {nullptr}; //Callbacks void clear (); @@ -52,20 +78,22 @@ public: //Helper inline void performAction(const CredentialModel::EditAction action); + CredentialNode* getCategory(Credential::Type type); + CredentialNode* createCat(const QString& name); }; #define CMP &CredentialModelPrivate Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> CredentialModelPrivate::m_mStateMachine ={{ - /* SAVE MODIFY RELOAD CLEAR */ - /* LOADING */ {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }}, - /* READY */ {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }}, - /* MODIFIED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}, - /* OUTDATED */ {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}, + /* SAVE MODIFY RELOAD CLEAR */ + { CredentialModel::EditState::LOADING , {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }}}, + { CredentialModel::EditState::READY , {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }}}, + { CredentialModel::EditState::MODIFIED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}}, + { CredentialModel::EditState::OUTDATED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}}, }}; #undef CMP ///Constructor -CredentialModel::CredentialModel(Account* acc) : QAbstractListModel(acc), +CredentialModel::CredentialModel(Account* acc) : QAbstractItemModel(acc), d_ptr(new CredentialModelPrivate()) { Q_ASSERT(acc); @@ -79,8 +107,8 @@ d_ptr(new CredentialModelPrivate()) CredentialModel::~CredentialModel() { - foreach (Credential* data, d_ptr->m_lCredentials) { - delete data; + foreach (CredentialNode* data, d_ptr->m_lCategories) { + free(data); //delete doesn't support non-trivial structures } } @@ -97,61 +125,138 @@ QHash<int,QByteArray> CredentialModel::roleNames() const 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 QVariant CredentialModel::data(const QModelIndex& idx, int role) const { if (!idx.isValid()) return QVariant(); - if (idx.column() == 0) { - switch (role) { - case Qt::DisplayRole: - return QVariant(d_ptr->m_lCredentials[idx.row()]->username()); - case CredentialModel::Role::NAME: - return d_ptr->m_lCredentials[idx.row()]->username(); - case CredentialModel::Role::PASSWORD: - return d_ptr->m_lCredentials[idx.row()]->password(); - case CredentialModel::Role::REALM: - return d_ptr->m_lCredentials[idx.row()]->realm(); - default: - break; - } + const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); + + switch (node->m_Level) { + case CredentialNode::Level::CATEGORY: + switch(role) { + case Qt::DisplayRole: + return *node->m_uContent.m_Category.m_CategoryName; + } + break; + case CredentialNode::Level::CREDENTIAL: + switch (role) { + 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(); } ///Number of credentials int CredentialModel::rowCount(const QModelIndex& par) const { - Q_UNUSED(par) - return d_ptr->m_lCredentials.size(); + if (!par.isValid()) + 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 Qt::ItemFlags CredentialModel::flags(const QModelIndex& idx) const { - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) /*| Qt::ItemIsUserCheckable*/ | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return QAbstractItemModel::flags(idx); + if (!idx.isValid()) + return Qt::NoItemFlags; + + 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 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; + + 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) { - d_ptr->m_lCredentials[idx.row()]->setUsername(value.toString()); + node->m_uContent.m_Cred.m_pCredential->setUsername(value.toString()); emit dataChanged(idx, idx); this << EditAction::MODIFY; return true; } else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) { - if (d_ptr->m_lCredentials[idx.row()]->password() != value.toString()) { - d_ptr->m_lCredentials[idx.row()]->setPassword(value.toString()); + if (node->m_uContent.m_Cred.m_pCredential->password() != value.toString()) { + node->m_uContent.m_Cred.m_pCredential->setPassword(value.toString()); emit dataChanged(idx, idx); this << EditAction::MODIFY; return true; } } 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); this << EditAction::MODIFY; return true; @@ -159,27 +264,92 @@ bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, in 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 -QModelIndex CredentialModel::addCredentials() +QModelIndex CredentialModel::addCredentials(Credential::Type type) { - beginInsertRows(QModelIndex(), d_ptr->m_lCredentials.size()-1, d_ptr->m_lCredentials.size()-1); - d_ptr->m_lCredentials << new Credential(Credential::Type::SIP); + CredentialNode* par = d_ptr->getCategory(type); + 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(); - emit dataChanged(index(d_ptr->m_lCredentials.size()-1,0), index(d_ptr->m_lCredentials.size()-1,0)); + this << EditAction::MODIFY; - return index(d_ptr->m_lCredentials.size()-1,0); + + return index(count, 0, parIdx); } ///Remove credential at 'idx' void CredentialModel::removeCredentials(const QModelIndex& idx) { - if (idx.isValid()) { - beginRemoveRows(QModelIndex(), idx.row(), idx.row()); - Credential* d = d_ptr->m_lCredentials[idx.row()]; - d_ptr->m_lCredentials.removeAt(idx.row()); - delete d; + if (idx.isValid() && idx.parent().isValid()) { + beginRemoveRows(idx.parent(), idx.row(), idx.row()); + + CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); + + 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(); - emit dataChanged(idx, index(d_ptr->m_lCredentials.size()-1,0)); + this << EditAction::MODIFY; } else { @@ -190,10 +360,12 @@ void CredentialModel::removeCredentials(const QModelIndex& idx) ///Remove everything void CredentialModelPrivate::clear() { - foreach(Credential* data2, m_lCredentials) { - delete data2; + q_ptr->beginRemoveRows(QModelIndex(),0,q_ptr->rowCount()); + foreach(CredentialNode* data2, m_lCategories) { + free_node(data2); } - m_lCredentials.clear(); + m_lCategories.clear(); + q_ptr->endRemoveRows(); m_EditState = CredentialModel::EditState::READY; } @@ -233,7 +405,7 @@ void CredentialModelPrivate::reload() ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); const VectorMapStringString credentials = configurationManager.getCredentials(m_pAccount->id()); 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::PASSWORD ],CredentialModel::Role::PASSWORD); q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM ); @@ -255,7 +427,7 @@ void CredentialModelPrivate::modify() 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 diff --git a/src/credentialmodel.h b/src/credentialmodel.h index 534f4e8544354b9637b7d7cc8c0ef4cbaea768f6..625e57ff2bee362b71d75db1a185150740db8d54 100644 --- a/src/credentialmodel.h +++ b/src/credentialmodel.h @@ -17,16 +17,21 @@ ***************************************************************************/ #pragma once -#include <QtCore/QString> #include <QtCore/QAbstractListModel> + #include "typedefs.h" +//Qt +#include <QtCore/QString> + +//Ring +#include <credential.h> class CredentialModelPrivate; class Account; ///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 ignored "-Wzero-as-null-pointer-constant" Q_OBJECT @@ -62,14 +67,17 @@ public: 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; + 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 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 - QModelIndex addCredentials(); + QModelIndex addCredentials(Credential::Type type); void removeCredentials(const QModelIndex& idx); bool performAction(CredentialModel::EditAction action);