From 180d44199aa35de656b7b8bdb41c8bfb06f0e9fd Mon Sep 17 00:00:00 2001
From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>
Date: Thu, 23 Apr 2015 11:06:04 -0400
Subject: [PATCH] autocompletion: Add the dialing number to the choices

Refs #71035
---
 src/account.cpp               |  28 ++++-----
 src/account.h                 |  26 ++++----
 src/accountmodel.cpp          |  12 ++--
 src/accountmodel.h            |   2 +
 src/contactmethod.cpp         |   5 ++
 src/contactmethod.h           |   4 +-
 src/numbercompletionmodel.cpp | 112 ++++++++++++++++++++++++++++++++--
 src/useractionmodel.cpp       |   9 +--
 8 files changed, 157 insertions(+), 41 deletions(-)

diff --git a/src/account.cpp b/src/account.cpp
index 30858f1d..839930f2 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -432,22 +432,22 @@ BootstrapModel* Account::bootstrapModel() const
    return d_ptr->m_pBootstrapModel;
 }
 
-bool Account::haveCalled() const
+bool Account::isUsedForOutgogingCall() const
 {
    return d_ptr->m_HaveCalled;
 }
 
-uint Account::totalCount() const
+uint Account::totalCallCount() const
 {
    return d_ptr->m_TotalCount;
 }
 
-uint Account::lastWeekCount() const
+uint Account::weekCallCount() const
 {
    return d_ptr->m_LastWeekCount;
 }
 
-uint Account::lastTrimCount() const
+uint Account::trimesterCallCount() const
 {
    return d_ptr->m_LastTrimCount;
 }
@@ -961,16 +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 ();
+      case CAST(Account::Role::UsedForOutgogingCall):
+         return isUsedForOutgogingCall();
+      case CAST(Account::Role::TotalCallCount):
+         return totalCallCount();
+      case CAST(Account::Role::WeekCallCount):
+         return weekCallCount();
+      case CAST(Account::Role::TrimesterCallCount):
+         return trimesterCallCount();
+      case CAST(Account::Role::LastUsed):
+         return (int)lastUsed();
       default:
          return QVariant();
    }
diff --git a/src/account.h b/src/account.h
index 45554484..3476be4a 100644
--- a/src/account.h
+++ b/src/account.h
@@ -141,10 +141,10 @@ 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(bool           usedForOutgogingCall         READ isUsedForOutgogingCall                                             )
+   Q_PROPERTY(uint           totalCallCount               READ totalCallCount                                                     )
+   Q_PROPERTY(uint           weekCallCount                READ weekCallCount                                                      )
+   Q_PROPERTY(uint           trimesterCallCount           READ trimesterCallCount                                                 )
    Q_PROPERTY(time_t         lastUsed                     READ lastUsed                                                           )
 
    public:
@@ -225,10 +225,10 @@ class LIB_EXPORT Account : public QObject {
          PresenceMessage             = 143,
          RegistrationState           = 144,
          UseDefaultPort              = 145,
-         HaveCalled                  = 146,
-         TotalCount                  = 147,
-         LastWeekCount               = 148,
-         LastTrimCount               = 149,
+         UsedForOutgogingCall        = 146,
+         TotalCallCount              = 147,
+         WeekCallCount               = 148,
+         TrimesterCallCount          = 149,
          LastUsed                    = 150,
       };
 
@@ -327,11 +327,11 @@ 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;
+      bool   isUsedForOutgogingCall () const;
+      uint   totalCallCount         () const;
+      uint   weekCallCount          () const;
+      uint   trimesterCallCount     () const;
+      time_t lastUsed               () const;
 
       Q_INVOKABLE QVariant roleData ( int role             ) const;
       Q_INVOKABLE bool supportScheme( URI::SchemeType type )      ;
diff --git a/src/accountmodel.cpp b/src/accountmodel.cpp
index 9f331ad3..87200504 100644
--- a/src/accountmodel.cpp
+++ b/src/accountmodel.cpp
@@ -142,10 +142,10 @@ 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::UsedForOutgogingCall        ) ,QByteArray("usedForOutgogingCall"          ));
+      roles.insert(CAST(Account::Role::TotalCallCount              ) ,QByteArray("totalCallCount"                ));
+      roles.insert(CAST(Account::Role::WeekCallCount               ) ,QByteArray("weekCallCount"                 ));
+      roles.insert(CAST(Account::Role::TrimesterCallCount          ) ,QByteArray("trimesterCallCount"            ));
       roles.insert(CAST(Account::Role::LastUsed                    ) ,QByteArray("lastUsed"                      ));
    }
    return roles;
@@ -403,6 +403,8 @@ void AccountModel::updateAccounts()
 
          if (a->id() != DRing::Account::ProtocolNames::IP2IP)
             d_ptr->enableProtocol(a->protocol());
+
+         emit accountAdded(a);
       }
       else {
          acc->performAction(Account::EditAction::RELOAD);
@@ -673,6 +675,8 @@ Account* AccountModel::add(const QString& alias, const Account::Protocol proto)
    if (a->id() != DRing::Account::ProtocolNames::IP2IP)
       d_ptr->enableProtocol(proto);
 
+   emit accountAdded(a);
+
    return a;
 }
 
diff --git a/src/accountmodel.h b/src/accountmodel.h
index e6f51857..1451f857 100644
--- a/src/accountmodel.h
+++ b/src/accountmodel.h
@@ -133,6 +133,8 @@ Q_SIGNALS:
    void presenceEnabledChanged(bool isPresent                        );
    ///An account has been removed
    void accountRemoved(Account* account                              );
+   ///An account has been added
+   void accountAdded(Account* account                                );
    ///Emitted when an account using a previously unsupported protocol is added
    void supportedProtocolsChanged(                                   );
    ///Emitted when an account state change
diff --git a/src/contactmethod.cpp b/src/contactmethod.cpp
index 82f7e2cc..458be763 100644
--- a/src/contactmethod.cpp
+++ b/src/contactmethod.cpp
@@ -415,6 +415,11 @@ QVariant ContactMethod::icon() const
    return category()->icon(isTracked(),isPresent());
 }
 
+QVariant TemporaryContactMethod::icon() const
+{
+   return QVariant(); //TODO use the pixmap delegate to get a better icon
+}
+
 ///The number of seconds spent with the URI (from history)
 int ContactMethod::totalSpentTime() const
 {
diff --git a/src/contactmethod.h b/src/contactmethod.h
index 9b3c50d0..faaf10b8 100644
--- a/src/contactmethod.h
+++ b/src/contactmethod.h
@@ -108,7 +108,7 @@ public:
    QString             primaryName     () const;
    bool                isBookmarked    () const;
    bool                supportPresence () const;
-   QVariant            icon            () const;
+   virtual QVariant    icon            () const;
    int                 totalSpentTime  () const;
    QString             uid             () const;
    URI::ProtocolHint   protocolHint    () const;
@@ -208,7 +208,9 @@ class LIB_EXPORT TemporaryContactMethod : public ContactMethod {
    Q_OBJECT
 public:
    explicit TemporaryContactMethod(const ContactMethod* number = nullptr);
+   virtual QVariant icon() const override;
    void setUri(const URI& uri);
+
 };
 
 #endif
diff --git a/src/numbercompletionmodel.cpp b/src/numbercompletionmodel.cpp
index 2b4ebc5a..e94730fd 100644
--- a/src/numbercompletionmodel.cpp
+++ b/src/numbercompletionmodel.cpp
@@ -63,6 +63,7 @@ public:
    void locateNameRange  (const QString& prefix, QSet<ContactMethod*>& set);
    void locateNumberRange(const QString& prefix, QSet<ContactMethod*>& set);
    uint getWeight(ContactMethod* number);
+   uint getWeight(Account* account);
    void getRange(QMap<QString,NumberWrapper*> map, const QString& prefix, QSet<ContactMethod*>& set) const;
 
    //Attributes
@@ -77,6 +78,9 @@ public:
 public Q_SLOTS:
    void setPrefix(const QString& str);
 
+   bool accountAdded  (Account* a);
+   void accountRemoved(Account* a);
+
 private:
    NumberCompletionModel* q_ptr;
 };
@@ -85,15 +89,44 @@ private:
 NumberCompletionModelPrivate::NumberCompletionModelPrivate(NumberCompletionModel* parent) : QObject(parent), q_ptr(parent),
 m_pCall(nullptr),m_Enabled(false),m_UseUnregisteredAccount(true)
 {
+   //Create the temporary number list
+   bool     hasNonIp2Ip = false;
+   Account* ip2ip       = AccountModel::instance()->ip2ip();
+
+   for (int i =0; i < AccountModel::instance()->size();i++) {
+      Account* a = (*AccountModel::instance())[i];
+      if (a != ip2ip) {
+         hasNonIp2Ip |= accountAdded(a);
+      }
+   }
+
+   //If SIP accounts are present, IP2IP is not needed
+   if (!hasNonIp2Ip) {
+      TemporaryContactMethod* cm = new TemporaryContactMethod();
+      cm->setAccount(ip2ip);
+      m_hSipIaxTemporaryNumbers[ip2ip] = cm;
+   }
+
+   connect(AccountModel::instance(), &AccountModel::accountAdded  , this, &NumberCompletionModelPrivate::accountAdded  );
+   connect(AccountModel::instance(), &AccountModel::accountRemoved, this, &NumberCompletionModelPrivate::accountRemoved);
 }
 
-NumberCompletionModel::NumberCompletionModel() : QAbstractTableModel(QCoreApplication::instance()), d_ptr(new NumberCompletionModelPrivate(this))
+NumberCompletionModel::NumberCompletionModel() : QAbstractTableModel(PhoneDirectoryModel::instance()), d_ptr(new NumberCompletionModelPrivate(this))
 {
    setObjectName("NumberCompletionModel");
 }
 
 NumberCompletionModel::~NumberCompletionModel()
 {
+   QList<TemporaryContactMethod*> l = d_ptr->m_hSipIaxTemporaryNumbers.values();
+
+   d_ptr->m_hSipIaxTemporaryNumbers.clear();
+
+   while(l.size()) {
+      TemporaryContactMethod* cm = l.takeAt(0);
+      delete cm;
+   }
+
    delete d_ptr;
 }
 
@@ -131,7 +164,9 @@ QVariant NumberCompletionModel::data(const QModelIndex& index, int role ) const
                return n->uri();
                break;
             case Qt::ToolTipRole:
-               return QString("<table><tr><td>%1</td></tr><tr><td>%2</td></tr></table>").arg(n->primaryName()).arg(n->category()->name());
+               return QString("<table><tr><td>%1</td></tr><tr><td>%2</td></tr></table>")
+                  .arg(n->primaryName())
+                  .arg(n->category() ? n->category()->name() : QString());
                break;
             case Qt::DecorationRole:
                return n->icon();
@@ -250,6 +285,10 @@ void NumberCompletionModelPrivate::setPrefix(const QString& str)
       m_hNumbers.clear();
       q_ptr->endRemoveRows();
    }
+
+   for(TemporaryContactMethod* cm : m_hSipIaxTemporaryNumbers) {
+      cm->setUri(str);
+   }
 }
 
 Call* NumberCompletionModel::call() const
@@ -260,7 +299,11 @@ Call* NumberCompletionModel::call() const
 ContactMethod* NumberCompletionModel::number(const QModelIndex& idx) const
 {
    if (idx.isValid()) {
-      return (d_ptr->m_hNumbers.end()-1-idx.row()).value();
+      //Keep the temporary contact methods private, export a copy
+      ContactMethod* m = (d_ptr->m_hNumbers.end()-1-idx.row()).value();
+      return m->type() == ContactMethod::Type::TEMPORARY ? 
+         PhoneDirectoryModel::instance()->fromTemporary(qobject_cast<TemporaryContactMethod*>(m))
+         : m;
    }
 
    return nullptr;
@@ -277,7 +320,16 @@ void NumberCompletionModelPrivate::updateModel()
       locateNameRange  ( m_Prefix, numbers );
       locateNumberRange( m_Prefix, numbers );
 
-      foreach(ContactMethod* n,numbers) {
+      for (TemporaryContactMethod* cm : m_hSipIaxTemporaryNumbers) {
+         const int weight = getWeight(cm->account());
+         if (weight) {
+            q_ptr->beginInsertRows(QModelIndex(), m_hNumbers.size(), m_hNumbers.size());
+            m_hNumbers.insert(weight,cm);
+            q_ptr->endInsertRows();
+         }
+      }
+
+      for (ContactMethod* n : numbers) {
          if (m_UseUnregisteredAccount || ((n->account() && n->account()->registrationState() == Account::RegistrationState::READY)
           || !n->account())) {
             q_ptr->beginInsertRows(QModelIndex(), m_hNumbers.size(), m_hNumbers.size());
@@ -375,8 +427,8 @@ void NumberCompletionModelPrivate::locateNumberRange(const QString& prefix, QSet
 
 uint NumberCompletionModelPrivate::getWeight(ContactMethod* number)
 {
-   Q_UNUSED(number)
    uint weight = 1;
+
    weight += (number->weekCount()+1)*150;
    weight += (number->trimCount()+1)*75 ;
    weight += (number->callCount()+1)*35 ;
@@ -386,6 +438,21 @@ uint NumberCompletionModelPrivate::getWeight(ContactMethod* number)
    return weight;
 }
 
+uint NumberCompletionModelPrivate::getWeight(Account* account)
+{
+   if ((!account) || account->registrationState() != Account::RegistrationState::READY)
+      return 0; //TODO handle the case where the account get registered during dialing
+
+   uint weight = 1;
+
+   weight += (account->weekCallCount         ()+1)*15;
+   weight += (account->trimesterCallCount    ()+1)*7 ;
+   weight += (account->totalCallCount        ()+1)*3 ;
+   weight *= (account->isUsedForOutgogingCall()?3:1 );
+
+   return weight;
+}
+
 QString NumberCompletionModel::prefix() const
 {
    return d_ptr->m_Prefix;
@@ -401,4 +468,39 @@ bool NumberCompletionModel::isUsingUnregisteredAccounts()
    return d_ptr->m_UseUnregisteredAccount;
 }
 
+bool NumberCompletionModelPrivate::accountAdded(Account* a)
+{
+   bool hasNonIp2Ip = false;
+
+   switch(a->protocol()) {
+      case Account::Protocol::SIP :
+         hasNonIp2Ip = true;
+         //no break
+      case Account::Protocol::IAX : {
+         TemporaryContactMethod* cm = new TemporaryContactMethod();
+         cm->setAccount(a);
+         m_hSipIaxTemporaryNumbers[a] = cm;
+         }
+         break;
+      case Account::Protocol::RING:
+      case Account::Protocol::COUNT__:
+         break;
+   }
+
+   return hasNonIp2Ip;
+}
+
+void NumberCompletionModelPrivate::accountRemoved(Account* a)
+{
+   TemporaryContactMethod* cm = m_hSipIaxTemporaryNumbers[a];
+
+   m_hSipIaxTemporaryNumbers[a] = nullptr;
+
+   setPrefix(q_ptr->prefix());
+
+   if (cm) {
+      delete cm;
+   }
+}
+
 #include <numbercompletionmodel.moc>
diff --git a/src/useractionmodel.cpp b/src/useractionmodel.cpp
index 069a5cdc..885fbdb8 100644
--- a/src/useractionmodel.cpp
+++ b/src/useractionmodel.cpp
@@ -439,11 +439,12 @@ void UserActionModelPrivate::updateCheckMask(int& ret, UserActionModel::Action a
 
 bool UserActionModelPrivate::updateByCall(UserActionModel::Action action, const Call* c)
 {
+   Account* a = c->account() ? c->account() : AvailableAccountModel::instance()->currentDefaultAccount();
    return (!c) ? false : (
-      availableActionMap        [action] [c->state()                       ] &&
-      availableAccountActionMap [action] [c->account()->registrationState()] &&
-      multi_call_options        [action] [m_SelectionState                 ] &&
-      availableProtocolActions  [action] [c->account()->protocol()         ] //
+      availableActionMap        [action] [c->state()             ] &&
+      availableAccountActionMap [action] [a->registrationState() ] &&
+      multi_call_options        [action] [m_SelectionState       ] &&
+      availableProtocolActions  [action] [a->protocol()          ] //
    );
 }
 
-- 
GitLab