Skip to content
Snippets Groups Projects
Select Git revision
  • aeb4a5c5af0966ca52459158cd78b8e017884a24
  • master default protected
  • release/201811
  • release/201812
  • release/201901
  • release/201902
  • release/201903
  • release/201904
  • release/201905
  • release/201906
  • release/201908
  • release/201912
  • release/202001
  • release/202005
  • release/windows-test/201910
  • release/201808
  • wip/smartlist_refacto
  • wip/patches_poly_2017/JimmyHamel/MathieuGirouxHuppe
18 results

App.xaml.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    accountlistmodel.cpp 23.76 KiB
    /****************************************************************************
     *   Copyright (C) 2009-2013 by Savoir-Faire Linux                          *
     *   Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com>          *
     *            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/>.  *
     ***************************************************************************/
    
    //Parent
    #include "accountlistmodel.h"
     
    //SFLPhone
    #include "sflphone_const.h"
    
    //Qt
    #include <QtCore/QObject>
    
    //SFLPhone library
    #include "dbus/configurationmanager.h"
    #include "dbus/callmanager.h"
    #include "visitors/accountlistcolorvisitor.h"
    
    AccountListModel* AccountListModel::m_spAccountList   = nullptr;
    Account*     AccountListModel::m_spPriorAccount   = nullptr     ;
    
    QVariant AccountListNoCheckProxyModel::data(const QModelIndex& idx,int role ) const
    {
       if (role == Qt::CheckStateRole) {
          return QVariant();
       }
       return AccountListModel::instance()->data(idx,role);
    }
    
    bool AccountListNoCheckProxyModel::setData( const QModelIndex& idx, const QVariant &value, int role)
    {
       return AccountListModel::instance()->setData(idx,value,role);
    }
    
    Qt::ItemFlags AccountListNoCheckProxyModel::flags (const QModelIndex& idx) const
    {
       const QModelIndex& src = AccountListModel::instance()->index(idx.row(),idx.column());
       if (!idx.row() || AccountListModel::instance()->data(src,Qt::CheckStateRole) == Qt::Unchecked)
          return Qt::NoItemFlags;
       return AccountListModel::instance()->flags(idx);
    }
    
    int AccountListNoCheckProxyModel::rowCount(const QModelIndex& parentIdx ) const
    {
       return AccountListModel::instance()->rowCount(parentIdx);
    }
    
    ///Constructors
    ///@param fill Whether to fill the list with accounts from configurationManager or not.
    AccountListModel::AccountListModel() : QAbstractListModel(QCoreApplication::instance()),m_pColorVisitor(nullptr),m_pDefaultAccount(nullptr)
    {
       setupRoleName();
    }
    
    ///Prevent constructor loop
    void AccountListModel::init()
    {
       updateAccounts();
       CallManagerInterface& callManager = DBus::CallManager::instance();
       ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
    
       connect(&callManager         , SIGNAL(registrationStateChanged(QString,QString,int)),this,SLOT(accountChanged(QString,QString,int)));
       connect(&configurationManager, SIGNAL(accountsChanged())                            ,this,SLOT(updateAccounts())                   );
       connect(&callManager         , SIGNAL(voiceMailNotify(QString,int))                 ,this, SLOT(slotVoiceMailNotify(QString,int))  );
    
    }
    
    ///Destructor
    AccountListModel::~AccountListModel()
    {
       while(m_lAccounts.size()) {
          Account* a = m_lAccounts[0];
          m_lAccounts.remove(0);
          delete a;
       }
    }
    
    void AccountListModel::setupRoleName()
    {
       QHash<int, QByteArray> roles = roleNames();
       roles.insert(Account::Role::Alias                    ,QByteArray("alias"                         ));
       roles.insert(Account::Role::Proto                    ,QByteArray("protocol"                      ));
       roles.insert(Account::Role::Hostname                 ,QByteArray("hostname"                      ));
       roles.insert(Account::Role::Username                 ,QByteArray("username"                      ));
       roles.insert(Account::Role::Mailbox                  ,QByteArray("mailbox"                       ));
       roles.insert(Account::Role::Proxy                    ,QByteArray("proxy"                         ));
       roles.insert(Account::Role::TlsPassword              ,QByteArray("tlsPassword"                   ));
       roles.insert(Account::Role::TlsCaListFile            ,QByteArray("tlsCaListFile"                 ));
       roles.insert(Account::Role::TlsCertificateFile       ,QByteArray("tlsCertificateFile"            ));
       roles.insert(Account::Role::TlsPrivateKeyFile        ,QByteArray("tlsPrivateKeyFile"             ));
       roles.insert(Account::Role::TlsCiphers               ,QByteArray("tlsCiphers"                    ));
       roles.insert(Account::Role::TlsServerName            ,QByteArray("tlsServerName"                 ));
       roles.insert(Account::Role::SipStunServer            ,QByteArray("sipStunServer"                 ));
       roles.insert(Account::Role::PublishedAddress         ,QByteArray("publishedAddress"              ));
       roles.insert(Account::Role::LocalInterface           ,QByteArray("localInterface"                ));
       roles.insert(Account::Role::RingtonePath             ,QByteArray("ringtonePath"                  ));
       roles.insert(Account::Role::TlsMethod                ,QByteArray("tlsMethod"                     ));
       roles.insert(Account::Role::RegistrationExpire       ,QByteArray("registrationExpire"            ));
       roles.insert(Account::Role::TlsNegotiationTimeoutSec ,QByteArray("tlsNegotiationTimeoutSec"      ));
       roles.insert(Account::Role::TlsNegotiationTimeoutMsec,QByteArray("tlsNegotiationTimeoutMsec"     ));
       roles.insert(Account::Role::LocalPort                ,QByteArray("localPort"                     ));
       roles.insert(Account::Role::TlsListenerPort          ,QByteArray("tlsListenerPort"               ));
       roles.insert(Account::Role::PublishedPort            ,QByteArray("publishedPort"                 ));
       roles.insert(Account::Role::Enabled                  ,QByteArray("enabled"                       ));
       roles.insert(Account::Role::AutoAnswer               ,QByteArray("autoAnswer"                    ));
       roles.insert(Account::Role::TlsVerifyServer          ,QByteArray("tlsVerifyServer"               ));
       roles.insert(Account::Role::TlsVerifyClient          ,QByteArray("tlsVerifyClient"               ));
       roles.insert(Account::Role::TlsRequireClientCertificate,QByteArray("tlsRequireClientCertificate" ));
       roles.insert(Account::Role::TlsEnable                ,QByteArray("tlsEnable"                     ));
       roles.insert(Account::Role::DisplaySasOnce           ,QByteArray("displaySasOnce"                ));
       roles.insert(Account::Role::SrtpRtpFallback          ,QByteArray("srtpRtpFallback"               ));
       roles.insert(Account::Role::ZrtpDisplaySas           ,QByteArray("zrtpDisplaySas"                ));
       roles.insert(Account::Role::ZrtpNotSuppWarning       ,QByteArray("zrtpNotSuppWarning"            ));
       roles.insert(Account::Role::ZrtpHelloHash            ,QByteArray("zrtpHelloHash"                 ));
       roles.insert(Account::Role::SipStunEnabled           ,QByteArray("sipStunEnabled"                ));
       roles.insert(Account::Role::PublishedSameAsLocal     ,QByteArray("publishedSameAsLocal"          ));
       roles.insert(Account::Role::RingtoneEnabled          ,QByteArray("ringtoneEnabled"               ));
       roles.insert(Account::Role::dTMFType                 ,QByteArray("dTMFType"                      ));
       roles.insert(Account::Role::Id                       ,QByteArray("id"                            ));
       roles.insert(Account::Role::Object                   ,QByteArray("object"                        ));
       roles.insert(Account::Role::TypeName                 ,QByteArray("typeName"                      ));
       roles.insert(Account::Role::PresenceStatus           ,QByteArray("presenceStatus"                ));
       roles.insert(Account::Role::PresenceMessage          ,QByteArray("presenceMessage"               ));
    
       setRoleNames(roles);
    }
    
    ///Singleton
    AccountListModel* AccountListModel::instance()
    {
       if (not m_spAccountList) {
          m_spAccountList = new AccountListModel();
          m_spAccountList->init();
       }
       return m_spAccountList;
    }
    
    ///Static destructor
    void AccountListModel::destroy()
    {
       if (m_spAccountList)
          delete m_spAccountList;
       m_spAccountList = nullptr;
    }
    
    ///Account status changed
    void AccountListModel::accountChanged(const QString& account,const QString& state, int code)
    {
       Account* a = getAccountById(account);
    
       if (!a || (a && a->registrationStatus() != state )) {
          if (state != "OK") //Do not polute the log
             qDebug() << "Account" << account << "status changed to" << state;
       }
       if (!a) {
          ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
          QStringList accountIds = configurationManager.getAccountList().value();
          for (int i = 0; i < accountIds.size(); ++i) {
             if ((!getAccountById(accountIds[i])) && m_lDeletedAccounts.indexOf(accountIds[i]) == -1) {
                Account* acc = Account::buildExistingAccountFromId(accountIds[i]);
                m_lAccounts.insert(i, acc);
                connect(acc,SIGNAL(changed(Account*)),this,SLOT(accountChanged(Account*)));
                emit dataChanged(index(i,0),index(size()-1));
                emit layoutChanged();
             }
          }
          foreach (Account* acc, m_lAccounts) {
             const int idx =accountIds.indexOf(acc->id());
             if (idx == -1 && (acc->state() == Account::AccountEditState::READY || acc->state() == Account::AccountEditState::REMOVED)) {
                m_lAccounts.remove(idx);
                emit dataChanged(index(idx - 1, 0), index(m_lAccounts.size()-1, 0));
                emit layoutChanged();
             }
          }
       }
       else {
          const bool isRegistered = a->isRegistered();
          a->updateState();
          emit a->stateChanged(a->toHumanStateName());
          const QModelIndex idx = a->index();
          emit dataChanged(idx, idx);
          const bool regStateChanged = isRegistered != a->isRegistered();
          if (regStateChanged && (code == 502 || code == 503)) {
             emit badGateway();
          }
          else if (regStateChanged)
             emit accountRegistrationChanged(a,a->isRegistered());
    
          //Keep the error message
          a->setLastErrorMessage(state);
          a->setLastErrorCode(code);
    
          emit accountStateChanged(a,a->toHumanStateName());
       }
    
    }
    
    ///Tell the model something changed
    void AccountListModel::accountChanged(Account* a)
    {
       int idx = m_lAccounts.indexOf(a);
       if (idx != -1) {
          emit dataChanged(index(idx, 0), index(idx, 0));
       }
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Mutator                                  *
     *                                                                           *
     ****************************************************************************/
    
    
    ///When a new voice mail is available
    void AccountListModel::slotVoiceMailNotify(const QString &accountID, int count)
    {
       Account* a = getAccountById(accountID);
       if (a) {
          a->setVoiceMailCount(count);
          emit voiceMailNotify(a,count);
       }
    }
    
    ///Update accounts
    void AccountListModel::update()
    {
       ConfigurationManagerInterface & configurationManager = DBus::ConfigurationManager::instance();
       QList<Account*> tmp;
       for (int i = 0; i < m_lAccounts.size(); i++)
          tmp << m_lAccounts[i];
    
       for (int i = 0; i < tmp.size(); i++) {
          Account* current = tmp[i];
          if (!current->isNew() && (current->state() != Account::AccountEditState::NEW
             && current->state() != Account::AccountEditState::MODIFIED
             && current->state() != Account::AccountEditState::OUTDATED))
             removeAccount(current);
       }
       //ask for the list of accounts ids to the configurationManager
       const QStringList accountIds = configurationManager.getAccountList().value();
       for (int i = 0; i < accountIds.size(); ++i) {
          if (m_lDeletedAccounts.indexOf(accountIds[i]) == -1) {
             Account* a = Account::buildExistingAccountFromId(accountIds[i]);
             m_lAccounts.insert(i, a);
             emit dataChanged(index(i,0),index(size()-1,0));
             connect(a,SIGNAL(changed(Account*)),this,SLOT(accountChanged(Account*)));
             emit layoutChanged();
          }
       }
    } //update
    
    ///Update accounts
    void AccountListModel::updateAccounts()
    {
       qDebug() << "Updating all accounts";
       ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
       QStringList accountIds = configurationManager.getAccountList().value();
       //m_lAccounts.clear();
       for (int i = 0; i < accountIds.size(); ++i) {
          Account* acc = getAccountById(accountIds[i]);
          if (!acc) {
             Account* a = Account::buildExistingAccountFromId(accountIds[i]);
             m_lAccounts += a;
             connect(a,SIGNAL(changed(Account*)),this,SLOT(accountChanged(Account*)));
             emit dataChanged(index(size()-1,0),index(size()-1,0));
          }
          else {
             acc->performAction(Account::AccountEditAction::RELOAD);
          }
       }
       emit accountListUpdated();
    } //updateAccounts
    
    ///Save accounts details and reload it
    void AccountListModel::save()
    {
       ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
       const QStringList accountIds = QStringList(configurationManager.getAccountList().value());
    
       //create or update each account from accountList
       for (int i = 0; i < size(); i++) {
          Account* current = (*this)[i];
          current->performAction(Account::AccountEditAction::SAVE);
       }
    
       //remove accounts that are in the configurationManager but not in the client
       for (int i = 0; i < accountIds.size(); i++) {
          if(!getAccountById(accountIds[i])) {
             configurationManager.removeAccount(accountIds[i]);
          }
       }
    
       //Set account order
       QString order;
       for( int i = 0 ; i < size() ; i++)
          order += getAccountAt(i)->id() + '/';
       configurationManager.setAccountsOrder(order);
       m_lDeletedAccounts.clear();
    }
    
    ///Move account up
    bool AccountListModel::accountUp( int idx )
    {
       if(idx > 0 && idx <= rowCount()) {
          Account* account = getAccountAt(idx);
          m_lAccounts.remove(idx);
          m_lAccounts.insert(idx - 1, account);
          emit dataChanged(this->index(idx - 1, 0, QModelIndex()), this->index(idx, 0, QModelIndex()));
          emit layoutChanged();
          return true;
       }
       return false;
    }
    
    ///Move account down
    bool AccountListModel::accountDown( int idx )
    {
       if(idx >= 0 && idx < rowCount()) {
          Account* account = getAccountAt(idx);
          m_lAccounts.remove(idx);
          m_lAccounts.insert(idx + 1, account);
          emit dataChanged(this->index(idx, 0, QModelIndex()), this->index(idx + 1, 0, QModelIndex()));
          emit layoutChanged();
          return true;
       }
       return false;
    }
    
    ///Try to register all enabled accounts
    void AccountListModel::registerAllAccounts()
    {
       ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
       configurationManager.registerAllAccounts();
    }
    
    ///Cancel all modifications
    void AccountListModel::cancel() {
       foreach (Account* a, getAccounts()) {
          if (a->state() == Account::AccountEditState::MODIFIED || a->state() == Account::AccountEditState::OUTDATED)
             a->performAction(Account::AccountEditAction::CANCEL);
       }
       m_lDeletedAccounts.clear();
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Getters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Get all accounts
    const QVector<Account*>& AccountListModel::getAccounts()
    {
       return m_lAccounts;
    }
    
    ///Get a single account
    Account* AccountListModel::getAccountAt (int i) const
    {
       return m_lAccounts[i];
    }
    
    ///Get account using its ID
    Account* AccountListModel::getAccountById(const QString& id) const
    {
       Q_ASSERT(!id.isEmpty());
       for (int i = 0; i < m_lAccounts.size(); i++) {
          Account* acc = m_lAccounts[i];
          if (acc && !acc->isNew() && acc->id() == id)
             return acc;
       }
       return nullptr;
    }
    
    ///Get account with a specific state
    QVector<Account*> AccountListModel::getAccountsByState(const QString& state)
    {
       QVector<Account *> v;
       for (int i = 0; i < m_lAccounts.size(); i++) {
          Account* acc = m_lAccounts[i];
          if (acc->registrationStatus() == state)
             v += acc;
       }
       return v;
    }
    
    ///Get the first registerred account (default account)
    Account* AccountListModel::firstRegisteredAccount() const
    {
       for (int i = 0; i < m_lAccounts.count(); ++i) {
          Account* current = m_lAccounts[i];
          if(current && current->registrationStatus() == Account::State::REGISTERED && current->isEnabled())
             return current;
          else if (current && (current->registrationStatus() == Account::State::READY) && m_lAccounts.count() == 1)
             return current;
    //       else if (current && !(current->accountRegistrationStatus()() == ACCOUNT_STATE_READY)) {
    //          qDebug() << "Account " << ((current)?current->accountId():"") << " is not registered ("
    //          << ((current)?current->accountRegistrationStatus()():"") << ") State:"
    //          << ((current)?current->accountRegistrationStatus()():"");
    //       }
       }
       return nullptr;
    }
    
    ///Get the account size
    int AccountListModel::size() const
    {
       return m_lAccounts.size();
    }
    
    ///Return the current account
    Account* AccountListModel::currentAccount()
    {
       Account* priorAccount = m_spPriorAccount;
       if(priorAccount && priorAccount->registrationStatus() == Account::State::REGISTERED && priorAccount->isEnabled() ) {
          return priorAccount;
       }
       else {
          Account* a = instance()->firstRegisteredAccount();
          if (!a)
             a = instance()->getAccountById("IP2IP");
          instance()->setPriorAccount(a);
          return a;
       }
    } //getCurrentAccount
    
    ///Get data from the model
    QVariant AccountListModel::data ( const QModelIndex& idx, int role) const
    {
       if (!idx.isValid() || idx.row() < 0 || idx.row() >= rowCount())
          return QVariant();
    
       const Account* account = m_lAccounts[idx.row()];
       if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
          return QVariant(account->alias());
       else if(idx.column() == 0 && role == Qt::CheckStateRole)
          return QVariant(account->isEnabled() ? Qt::Checked : Qt::Unchecked);
       else if (role == Qt::BackgroundRole)
          return (m_pColorVisitor)?m_pColorVisitor->getColor(account):account->stateColor();
       else if(idx.column() == 0 && role == Qt::DecorationRole && m_pColorVisitor)
          return m_pColorVisitor->getIcon(account);
       else
          return account->roleData(role);
    } //data
    
    ///Flags for "idx"
    Qt::ItemFlags AccountListModel::flags(const QModelIndex& idx) const
    {
       if (idx.column() == 0)
          return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
       return QAbstractItemModel::flags(idx);
    }
    
    ///Number of account
    int AccountListModel::rowCount(const QModelIndex& parentIdx) const
    {
       Q_UNUSED(parentIdx);
       return m_lAccounts.size();
    }
    
    Account* AccountListModel::getAccountByModelIndex(const QModelIndex& item) const
    {
       if (!item.isValid())
          return nullptr;
       return m_lAccounts[item.row()];
    }
    
    AccountListColorVisitor* AccountListModel::colorVisitor()
    {
       return m_pColorVisitor;
    }
    
    ///Return the default account (used for contact lookup)
    Account* AccountListModel::getDefaultAccount() const
    {
       return m_pDefaultAccount;
    }
    
    ///Generate an unique suffix to prevent multiple account from sharing alias
    QString AccountListModel::getSimilarAliasIndex(const QString& alias)
    {
       int count = 0;
       foreach (Account* a, instance()->getAccounts()) {
          if (a->alias().left(alias.size()) == alias)
             count++;
       }
       bool found = true;
       do {
          found = false;
          foreach (Account* a, instance()->getAccounts()) {
             if (a->alias() == alias+QString(" (%1)").arg(count)) {
                count++;
                found = false;
                break;
             }
          }
       } while(found);
       if (count)
          return QString(" (%1)").arg(count);
       return QString();
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                  Setters                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Add an account
    Account* AccountListModel::addAccount(const QString& alias)
    {
       Account* a = Account::buildNewAccountFromAlias(alias);
       connect(a,SIGNAL(changed(Account*)),this,SLOT(accountChanged(Account*)));
       m_lAccounts += a;
    
       emit dataChanged(index(m_lAccounts.size()-1,0), index(m_lAccounts.size()-1,0));
       return a;
    }
    
    ///Remove an account
    void AccountListModel::removeAccount(Account* account)
    {
       if (not account) return;
       qDebug() << "Removing" << account->alias() << account->id();
       const int aindex = m_lAccounts.indexOf(account);
       m_lAccounts.remove(aindex);
       m_lDeletedAccounts << account->id();
       if (currentAccount() == account)
          setPriorAccount(getAccountById("IP2IP"));
       emit dataChanged(index(aindex,0), index(m_lAccounts.size()-1,0));
       emit layoutChanged();
       //delete account;
    }
    
    void AccountListModel::removeAccount( QModelIndex idx )
    {
       removeAccount(getAccountByModelIndex(idx));
    }
    
    ///Set the previous account used
    void AccountListModel::setPriorAccount(const Account* account) {
       const bool changed = (account && m_spPriorAccount != account) || (!account && m_spPriorAccount);
       m_spPriorAccount = const_cast<Account*>(account);
       if (changed)
          emit priorAccountChanged(currentAccount());
    }
    
    ///Set model data
    bool AccountListModel::setData(const QModelIndex& idx, const QVariant& value, int role)
    {
       if (idx.isValid() && idx.column() == 0 && role == Qt::CheckStateRole) {
          const bool prevEnabled = m_lAccounts[idx.row()]->isEnabled();
          m_lAccounts[idx.row()]->setEnabled(value.toBool());
          emit dataChanged(idx, idx);
          if (prevEnabled != value.toBool())
             emit accountEnabledChanged(m_lAccounts[idx.row()]);
          emit dataChanged(idx, idx);
          return true;
       }
       else if ( role == Qt::EditRole ) {
          if (value.toString() != data(idx,Qt::EditRole)) {
             m_lAccounts[idx.row()]->setAlias(value.toString());
             emit dataChanged(idx, idx);
          }
       }
       return false;
    }
    
    ///Set QAbstractItemModel BackgroundRole visitor
    void AccountListModel::setColorVisitor(AccountListColorVisitor* visitor)
    {
       m_pColorVisitor = visitor;
    }
    
    ///Set the default account (used for contact lookup)
    void AccountListModel::setDefaultAccount(Account* a)
    {
       if (a != m_pDefaultAccount)
          emit defaultAccountChanged(a);
       m_pDefaultAccount = a;
    }
    
    
    /*****************************************************************************
     *                                                                           *
     *                                 Operator                                  *
     *                                                                           *
     ****************************************************************************/
    
    ///Get the account from its index
    const Account* AccountListModel::operator[] (int i) const
    {
       return m_lAccounts[i];
    }
    
    ///Get the account from its index
    Account* AccountListModel::operator[] (int i)
    {
       return m_lAccounts[i];
    }
    
    ///Get accoutn by id
    Account* AccountListModel::operator[] (const QString& i) {
       return getAccountById(i);
    }