diff --git a/src/account.cpp b/src/account.cpp index 42c64fa69b26efec57519b0ed3dd2dd7769b26e6..30858f1dcec53c289b5b1064dae98dd6d5516d96 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -73,7 +73,8 @@ m_CurrentState(Account::EditState::READY), m_pAccountNumber(nullptr),m_pKeyExchangeModel(nullptr),m_pSecurityEvaluationModel(nullptr),m_pTlsMethodModel(nullptr), m_pCaCert(nullptr),m_pTlsCert(nullptr),m_pPrivateKey(nullptr),m_isLoaded(true),m_pCipherModel(nullptr), m_pStatusModel(nullptr),m_LastTransportCode(0),m_RegistrationState(Account::RegistrationState::UNREGISTERED), -m_UseDefaultPort(false),m_pProtocolModel(nullptr),m_pBootstrapModel(nullptr),m_RemoteEnabledState(false) +m_UseDefaultPort(false),m_pProtocolModel(nullptr),m_pBootstrapModel(nullptr),m_RemoteEnabledState(false), +m_HaveCalled(false),m_TotalCount(0),m_LastWeekCount(0),m_LastTrimCount(0),m_LastUsed(0) { Q_Q(Account); } @@ -431,6 +432,39 @@ BootstrapModel* Account::bootstrapModel() const return d_ptr->m_pBootstrapModel; } +bool Account::haveCalled() const +{ + return d_ptr->m_HaveCalled; +} + +uint Account::totalCount() const +{ + return d_ptr->m_TotalCount; +} + +uint Account::lastWeekCount() const +{ + return d_ptr->m_LastWeekCount; +} + +uint Account::lastTrimCount() const +{ + return d_ptr->m_LastTrimCount; +} + +time_t Account::lastUsed() const +{ + return d_ptr->m_LastUsed; +} + + + +/******************************************************************************* + * * + * Setters * + * * + ******************************************************************************/ + void Account::setAlias(const QString& detail) { const bool accChanged = detail != alias(); @@ -927,6 +961,16 @@ QVariant Account::roleData(int role) const return PresenceStatusModel::instance()->currentMessage(); case CAST(Account::Role::RegistrationState): return QVariant::fromValue(registrationState()); + case CAST(Account::Role::HaveCalled ): + return haveCalled (); + case CAST(Account::Role::TotalCount ): + return totalCount (); + case CAST(Account::Role::LastWeekCount): + return lastWeekCount (); + case CAST(Account::Role::LastTrimCount): + return lastTrimCount (); + case CAST(Account::Role::LastUsed ): + return (int)lastUsed (); default: return QVariant(); } diff --git a/src/account.h b/src/account.h index 0bbd73698d172ab9c626c3c081f8839307c607a8..4555448443a13c4fef505bb9a711a36a253e3321 100644 --- a/src/account.h +++ b/src/account.h @@ -81,6 +81,7 @@ class LIB_EXPORT Account : public QObject { friend class TlsMethodModelPrivate; friend class TlsMethodModel; friend class BootstrapModelPrivate; + friend class ContactMethod; //Properties Q_PROPERTY(QByteArray id READ id ) @@ -140,6 +141,11 @@ class LIB_EXPORT Account : public QObject { Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent ) Q_PROPERTY(bool useDefaultPort READ useDefaultPort WRITE setUseDefaultPort ) Q_PROPERTY(RegistrationState registrationState READ registrationState ) + Q_PROPERTY(bool haveCalled READ haveCalled ) + Q_PROPERTY(uint totalCount READ totalCount ) + Q_PROPERTY(uint lastWeekCount READ lastWeekCount ) + Q_PROPERTY(uint lastTrimCount READ lastTrimCount ) + Q_PROPERTY(time_t lastUsed READ lastUsed ) public: ///@enum EditState: Manage how and when an account can be reloaded or change state @@ -219,6 +225,11 @@ class LIB_EXPORT Account : public QObject { PresenceMessage = 143, RegistrationState = 144, UseDefaultPort = 145, + HaveCalled = 146, + TotalCount = 147, + LastWeekCount = 148, + LastTrimCount = 149, + LastUsed = 150, }; enum class Protocol { @@ -316,6 +327,12 @@ class LIB_EXPORT Account : public QObject { Protocol protocol () const; KeyExchangeModel::Type keyExchange () const; + bool haveCalled () const; + uint totalCount () const; + uint lastWeekCount () const; + uint lastTrimCount () const; + time_t lastUsed () const; + Q_INVOKABLE QVariant roleData ( int role ) const; Q_INVOKABLE bool supportScheme( URI::SchemeType type ) ; @@ -412,6 +429,7 @@ Q_DECLARE_METATYPE(Account*) Q_DECLARE_METATYPE(Account::RegistrationState) Q_DECLARE_METATYPE(Account::EditAction) Q_DECLARE_METATYPE(Account::Protocol) +Q_DECLARE_METATYPE(DtmfType) Account* operator<<(Account* a, Account::EditAction action); diff --git a/src/accountmodel.cpp b/src/accountmodel.cpp index 09a851c6203e1e38040717e5937b91e3c18eb40f..9f331ad3bf7a28a6496acfcb52f1c1b634fa4508 100644 --- a/src/accountmodel.cpp +++ b/src/accountmodel.cpp @@ -142,6 +142,11 @@ QHash<int,QByteArray> AccountModel::roleNames() const roles.insert(CAST(Account::Role::TypeName ) ,QByteArray("typeName" )); roles.insert(CAST(Account::Role::PresenceStatus ) ,QByteArray("presenceStatus" )); roles.insert(CAST(Account::Role::PresenceMessage ) ,QByteArray("presenceMessage" )); + roles.insert(CAST(Account::Role::HaveCalled ) ,QByteArray("haveCalled" )); + roles.insert(CAST(Account::Role::TotalCount ) ,QByteArray("totalCount" )); + roles.insert(CAST(Account::Role::LastWeekCount ) ,QByteArray("lastWeekCount" )); + roles.insert(CAST(Account::Role::LastTrimCount ) ,QByteArray("lastTrimCount" )); + roles.insert(CAST(Account::Role::LastUsed ) ,QByteArray("lastUsed" )); } return roles; } diff --git a/src/contactmethod.cpp b/src/contactmethod.cpp index 1d505aa2d0280421538053139fdca739d99d417c..82f7e2ccb31210b3237dc75991ba4658b88a39fc 100644 --- a/src/contactmethod.cpp +++ b/src/contactmethod.cpp @@ -19,6 +19,7 @@ #include "phonedirectorymodel.h" #include "person.h" #include "account.h" +#include "private/account_p.h" #include "call.h" #include "dbus/presencemanager.h" #include "numbercategorymodel.h" @@ -212,6 +213,18 @@ time_t ContactMethod::lastUsed() const ///Set this number default account void ContactMethod::setAccount(Account* account) { + + //Add the statistics + if (account && !d_ptr->m_pAccount) { + account->d_ptr->m_HaveCalled += d_ptr->m_HaveCalled ; + account->d_ptr->m_TotalCount += callCount() ; + account->d_ptr->m_LastWeekCount += d_ptr->m_LastWeekCount ; + account->d_ptr->m_LastTrimCount += d_ptr->m_LastTrimCount ; + + if (d_ptr->m_LastUsed > account->d_ptr->m_LastUsed) + account->d_ptr->m_LastUsed = d_ptr->m_LastUsed; + } + d_ptr->m_pAccount = account; if (d_ptr->m_pAccount) connect (d_ptr->m_pAccount,SIGNAL(destroyed(QObject*)),this,SLOT(accountDestroyed(QObject*))); @@ -456,23 +469,44 @@ QVariant ContactMethod::roleData(int role) const void ContactMethod::addCall(Call* call) { if (!call) return; + + //Update the contact method statistics d_ptr->m_Type = ContactMethod::Type::USED; d_ptr->m_lCalls << call; d_ptr->m_TotalSeconds += call->stopTimeStamp() - call->startTimeStamp(); time_t now; ::time ( &now ); - if (now - 3600*24*7 < call->stopTimeStamp()) + + if (now - 3600*24*7 < call->stopTimeStamp()) { d_ptr->m_LastWeekCount++; - if (now - 3600*24*7*15 < call->stopTimeStamp()) + if (d_ptr->m_pAccount) + d_ptr->m_pAccount->d_ptr->m_LastWeekCount++; + } + + if (now - 3600*24*7*15 < call->stopTimeStamp()) { d_ptr->m_LastTrimCount++; + if (d_ptr->m_pAccount) + d_ptr->m_pAccount->d_ptr->m_LastTrimCount++; + } - if (call->direction() == Call::Direction::OUTGOING) + if (call->direction() == Call::Direction::OUTGOING) { d_ptr->m_HaveCalled = true; + if (d_ptr->m_pAccount) + d_ptr->m_pAccount->d_ptr->m_HaveCalled = true; + } d_ptr->callAdded(call); - if (call->startTimeStamp() > d_ptr->m_LastUsed) + + if (call->startTimeStamp() > d_ptr->m_LastUsed) { d_ptr->m_LastUsed = call->startTimeStamp(); + if (d_ptr->m_pAccount && d_ptr->m_pAccount->d_ptr->m_LastUsed < d_ptr->m_LastUsed) + d_ptr->m_pAccount->d_ptr->m_LastUsed = d_ptr->m_LastUsed; + } + d_ptr->changed(); + + if (d_ptr->m_pAccount) + d_ptr->m_pAccount->d_ptr->m_TotalCount++; } ///Generate an unique representation of this number @@ -481,8 +515,6 @@ QString ContactMethod::toHash() const return QString("%1///%2///%3").arg(uri()).arg(account()?account()->id():QString()).arg(contact()?contact()->uid():QString()); } - - ///Increment name counter and update indexes void ContactMethod::incrementAlternativeName(const QString& name) { diff --git a/src/numbercompletionmodel.cpp b/src/numbercompletionmodel.cpp index 0ee0824fff8b1aca6674b9538536b3c0a613a3e9..2b4ebc5a2c1d1c22d24fdf2dffb7f60a6067220e 100644 --- a/src/numbercompletionmodel.cpp +++ b/src/numbercompletionmodel.cpp @@ -43,6 +43,7 @@ class NumberCompletionModelPrivate : public QObject { + Q_OBJECT public: enum class Columns { @@ -66,10 +67,15 @@ public: //Attributes QMultiMap<int,ContactMethod*> m_hNumbers ; - QString m_Prefix ; - Call* m_pCall ; - bool m_Enabled ; - bool m_UseUnregisteredAccount; + QString m_Prefix ; + Call* m_pCall ; + bool m_Enabled ; + bool m_UseUnregisteredAccount; + + QHash<Account*,TemporaryContactMethod*> m_hSipIaxTemporaryNumbers; + +public Q_SLOTS: + void setPrefix(const QString& str); private: NumberCompletionModel* q_ptr; @@ -88,19 +94,21 @@ NumberCompletionModel::NumberCompletionModel() : QAbstractTableModel(QCoreApplic NumberCompletionModel::~NumberCompletionModel() { - + delete d_ptr; } QHash<int,QByteArray> NumberCompletionModel::roleNames() const { static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); static bool initRoles = false; + if (!initRoles) { initRoles = true; roles[Role::ALTERNATE_ACCOUNT]= "AlternateAccount"; - roles[Role::FORCE_ACCOUNT ]= "ForceAccount"; - roles[Role::ACCOUNT ]= "Account"; + roles[Role::FORCE_ACCOUNT ]= "ForceAccount" ; + roles[Role::ACCOUNT ]= "Account" ; } + return roles; } @@ -164,6 +172,7 @@ QVariant NumberCompletionModel::data(const QModelIndex& index, int role ) const }; break; }; + return QVariant(); } @@ -171,6 +180,7 @@ int NumberCompletionModel::rowCount(const QModelIndex& parent ) const { if (parent.isValid()) return 0; + return d_ptr->m_hNumbers.size(); } @@ -178,21 +188,26 @@ int NumberCompletionModel::columnCount(const QModelIndex& parent ) const { if (parent.isValid()) return 0; + return 4; } Qt::ItemFlags NumberCompletionModel::flags(const QModelIndex& index ) const { - if (!index.isValid()) return Qt::NoItemFlags; + if (!index.isValid()) + return Qt::NoItemFlags; + return Qt::ItemIsEnabled|Qt::ItemIsSelectable; } QVariant NumberCompletionModel::headerData (int section, Qt::Orientation orientation, int role) const { - Q_UNUSED(section) Q_UNUSED(orientation) static const QString headers[] = {tr("URI"), tr("Name"), tr("Account"), tr("Weight")}; - if (role == Qt::DisplayRole) return headers[section]; + + if (role == Qt::DisplayRole) + return headers[section]; + return QVariant(); } @@ -208,27 +223,32 @@ bool NumberCompletionModel::setData(const QModelIndex& index, const QVariant &va void NumberCompletionModel::setCall(Call* call) { if (d_ptr->m_pCall) - disconnect(d_ptr->m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString))); + disconnect(d_ptr->m_pCall,SIGNAL(dialNumberChanged(QString)),d_ptr,SLOT(setPrefix(QString))); + d_ptr->m_pCall = call; + if (d_ptr->m_pCall) - connect(d_ptr->m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString))); - setPrefix(call?call->dialNumber():QString()); + connect(d_ptr->m_pCall,SIGNAL(dialNumberChanged(QString)),d_ptr,SLOT(setPrefix(QString))); + + d_ptr->setPrefix(call?call->dialNumber():QString()); } -void NumberCompletionModel::setPrefix(const QString& str) +void NumberCompletionModelPrivate::setPrefix(const QString& str) { - d_ptr->m_Prefix = str; - const bool e = ((d_ptr->m_pCall && d_ptr->m_pCall->lifeCycleState() == Call::LifeCycleState::CREATION) || (!d_ptr->m_pCall)) && (!str.isEmpty()); - if (d_ptr->m_Enabled != e) { - d_ptr->m_Enabled = e; - emit enabled(e); + m_Prefix = str; + const bool e = ((m_pCall && m_pCall->lifeCycleState() == Call::LifeCycleState::CREATION) || (!m_pCall)) && (!str.isEmpty()); + + if (m_Enabled != e) { + m_Enabled = e; + emit q_ptr->enabled(e); } - if (d_ptr->m_Enabled) - d_ptr->updateModel(); + + if (m_Enabled) + updateModel(); else { - beginRemoveRows(QModelIndex(), 0, d_ptr->m_hNumbers.size()-1); - d_ptr->m_hNumbers.clear(); - endRemoveRows(); + q_ptr->beginRemoveRows(QModelIndex(), 0, m_hNumbers.size()-1); + m_hNumbers.clear(); + q_ptr->endRemoveRows(); } } @@ -242,6 +262,7 @@ ContactMethod* NumberCompletionModel::number(const QModelIndex& idx) const if (idx.isValid()) { return (d_ptr->m_hNumbers.end()-1-idx.row()).value(); } + return nullptr; } @@ -251,6 +272,7 @@ void NumberCompletionModelPrivate::updateModel() q_ptr->beginRemoveRows(QModelIndex(), 0, m_hNumbers.size()-1); m_hNumbers.clear(); q_ptr->endRemoveRows(); + if (!m_Prefix.isEmpty()) { locateNameRange ( m_Prefix, numbers ); locateNumberRange( m_Prefix, numbers ); @@ -270,6 +292,7 @@ void NumberCompletionModelPrivate::getRange(QMap<QString,NumberWrapper*> map, co { if (prefix.isEmpty() || map.isEmpty()) return; + QMap<QString,NumberWrapper*>::iterator iBeg = map.begin(); QMap<QString,NumberWrapper*>::iterator iEnd = map.end ()-1; @@ -278,24 +301,31 @@ void NumberCompletionModelPrivate::getRange(QMap<QString,NumberWrapper*> map, co const int prefixLen = pref.size(); int size = map.size()/2; bool startOk(false),endOk(false); + while (size > 1 && !(startOk&&endOk)) { QMap<QString,NumberWrapper*>::iterator mid; + if (size > 7) mid = (iBeg+size); else { //We have to be careful with "::ceil" it may cause an overflow in some rare case int toAdd = size-1; mid = iBeg; + while (toAdd && mid != map.end()) { ++mid; --toAdd; } + } + if (mid != map.end() && mid.key().left(prefixLen) == pref && iBeg.key().left(prefixLen) < pref) { //Too far, need to go back iBeg = mid; + while ((iBeg-1).key().left(prefixLen) == pref && iBeg != map.begin()) iBeg--; + startOk = true; } else if ((!startOk) && mid != map.end() && mid.key().left(prefixLen) < pref) { @@ -321,12 +351,14 @@ void NumberCompletionModelPrivate::getRange(QMap<QString,NumberWrapper*> map, co iEnd = map.end(); iBeg = map.end(); } + while(iBeg != iEnd) { foreach(ContactMethod* n,iBeg.value()->numbers) { if (n) { set << n; } } + ++iBeg; } } @@ -350,6 +382,7 @@ uint NumberCompletionModelPrivate::getWeight(ContactMethod* number) weight += (number->callCount()+1)*35 ; weight *= (number->uri().indexOf(m_Prefix)!= -1?3:1); weight *= (number->isPresent()?2:1); + return weight; } diff --git a/src/numbercompletionmodel.h b/src/numbercompletionmodel.h index 66194460ae510d00296316f7bc542738d3596167..b7821032d31848995eae07699285565bbae45f50 100644 --- a/src/numbercompletionmodel.h +++ b/src/numbercompletionmodel.h @@ -35,7 +35,7 @@ class LIB_EXPORT NumberCompletionModel : public QAbstractTableModel { public: //Properties - Q_PROPERTY(QString prefix READ prefix WRITE setPrefix) + Q_PROPERTY(QString prefix READ prefix) enum Role { ALTERNATE_ACCOUNT= 100, @@ -67,13 +67,9 @@ public: QString prefix() const; private: - QScopedPointer<NumberCompletionModelPrivate> d_ptr; + NumberCompletionModelPrivate* d_ptr; Q_DECLARE_PRIVATE(NumberCompletionModel) - -public Q_SLOTS: - void setPrefix(const QString& str); - Q_SIGNALS: void enabled(bool); diff --git a/src/private/account_p.h b/src/private/account_p.h index 28cc5a773e72b8a800e1baa2db00c3552c84535a..69b1de3d4d54ba790f97a34c0a3d927aeee56f90 100644 --- a/src/private/account_p.h +++ b/src/private/account_p.h @@ -54,6 +54,7 @@ public: friend class TlsMethodModelPrivate; friend class TlsMethodModel; friend class BootstrapModelPrivate; + friend class ContactMethod; //Constructor explicit AccountPrivate(Account* acc); @@ -71,6 +72,13 @@ public: unsigned short m_UseDefaultPort ; bool m_RemoteEnabledState ; + //Statistic + bool m_HaveCalled ; + uint m_TotalCount ; + uint m_LastWeekCount ; + uint m_LastTrimCount ; + time_t m_LastUsed ; + //Setters void setAccountProperties(const QHash<QString,QString>& m ); bool setAccountProperty (const QString& param, const QString& val );