~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to kde/src/lib/numbercompletionmodel.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
 *   Copyright (C) 2013-2014 by Savoir-Faire Linux                          *
 
3
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
 
4
 *                                                                          *
 
5
 *   This library is free software; you can redistribute it and/or          *
 
6
 *   modify it under the terms of the GNU Lesser General Public             *
 
7
 *   License as published by the Free Software Foundation; either           *
 
8
 *   version 2.1 of the License, or (at your option) any later version.     *
 
9
 *                                                                          *
 
10
 *   This library is distributed in the hope that it will be useful,        *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
 
13
 *   Lesser General Public License for more details.                        *
 
14
 *                                                                          *
 
15
 *   You should have received a copy of the GNU General Public License      *
 
16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 
17
 ***************************************************************************/
 
18
#include "numbercompletionmodel.h"
 
19
 
 
20
//Qt
 
21
#include <QtCore/QCoreApplication>
 
22
 
 
23
//System
 
24
#include <cmath>
 
25
 
 
26
//SFLPhone
 
27
#include "phonedirectorymodel.h"
 
28
#include "phonenumber.h"
 
29
#include "call.h"
 
30
#include "numbercategory.h"
 
31
#include "accountlistmodel.h"
 
32
#include "numbercategorymodel.h"
 
33
#include "visitors/pixmapmanipulationvisitor.h"
 
34
 
 
35
NumberCompletionModel::NumberCompletionModel() : QAbstractTableModel(QCoreApplication::instance()),
 
36
   m_pCall(nullptr),m_Enabled(false),m_UseUnregisteredAccount(true)
 
37
{
 
38
   setObjectName("NumberCompletionModel");
 
39
}
 
40
 
 
41
NumberCompletionModel::~NumberCompletionModel()
 
42
{
 
43
   
 
44
}
 
45
 
 
46
QVariant NumberCompletionModel::data(const QModelIndex& index, int role ) const
 
47
{
 
48
   if (!index.isValid()) return QVariant();
 
49
   const QMap<int,PhoneNumber*>::iterator i = const_cast<NumberCompletionModel*>(this)->m_hNumbers.end()-1-index.row();
 
50
   const PhoneNumber* n = i.value();
 
51
   const int weight     = i.key  ();
 
52
 
 
53
   bool needAcc = (role>=100 || role == Qt::UserRole) && n->account() && n->account() != AccountListModel::instance()->currentAccount()
 
54
                  && n->account()->alias() != "IP2IP";
 
55
 
 
56
   switch (static_cast<NumberCompletionModel::Columns>(index.column())) {
 
57
      case NumberCompletionModel::Columns::CONTENT:
 
58
         switch (role) {
 
59
            case Qt::DisplayRole:
 
60
               return n->uri();
 
61
               break;
 
62
            case Qt::ToolTipRole:
 
63
               return QString("<table><tr><td>%1</td></tr><tr><td>%2</td></tr></table>").arg(n->primaryName()).arg(n->category()->name());
 
64
               break;
 
65
            case Qt::DecorationRole:
 
66
               return n->icon();
 
67
               break;
 
68
            case NumberCompletionModel::Role::ALTERNATE_ACCOUNT:
 
69
            case Qt::UserRole:
 
70
               if (needAcc)
 
71
                  return n->account()->alias();
 
72
               else
 
73
                  return QString();
 
74
            case NumberCompletionModel::Role::FORCE_ACCOUNT:
 
75
               return needAcc;
 
76
            case NumberCompletionModel::Role::ACCOUNT:
 
77
               if (needAcc)
 
78
                  return QVariant::fromValue(const_cast<Account*>(n->account()));
 
79
               break;
 
80
         };
 
81
         break;
 
82
      case NumberCompletionModel::Columns::NAME:
 
83
         switch (role) {
 
84
            case Qt::DisplayRole:
 
85
               return n->primaryName();
 
86
         };
 
87
         break;
 
88
      case NumberCompletionModel::Columns::ACCOUNT:
 
89
         switch (role) {
 
90
            case Qt::DisplayRole:
 
91
               return n->account()?n->account()->id():AccountListModel::instance()->currentAccount()->id();
 
92
         };
 
93
         break;
 
94
      case NumberCompletionModel::Columns::WEIGHT:
 
95
         switch (role) {
 
96
            case Qt::DisplayRole:
 
97
               return weight;
 
98
         };
 
99
         break;
 
100
   };
 
101
   return QVariant();
 
102
}
 
103
 
 
104
int NumberCompletionModel::rowCount(const QModelIndex& parent ) const
 
105
{
 
106
   if (parent.isValid())
 
107
      return 0;
 
108
   return m_hNumbers.size();
 
109
}
 
110
 
 
111
int NumberCompletionModel::columnCount(const QModelIndex& parent ) const
 
112
{
 
113
   if (parent.isValid())
 
114
      return 0;
 
115
   return 4;
 
116
}
 
117
 
 
118
Qt::ItemFlags NumberCompletionModel::flags(const QModelIndex& index ) const
 
119
{
 
120
   if (!index.isValid()) return Qt::NoItemFlags;
 
121
   return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
 
122
}
 
123
 
 
124
QVariant NumberCompletionModel::headerData (int section, Qt::Orientation orientation, int role) const
 
125
{
 
126
   Q_UNUSED(section)
 
127
   Q_UNUSED(orientation)
 
128
   static const QString headers[] = {tr("URI"), tr("Name"), tr("Account"), tr("Weight")};
 
129
   if (role == Qt::DisplayRole) return headers[section];
 
130
   return QVariant();
 
131
}
 
132
 
 
133
bool NumberCompletionModel::setData(const QModelIndex& index, const QVariant &value, int role)
 
134
{
 
135
   Q_UNUSED( index )
 
136
   Q_UNUSED( value )
 
137
   Q_UNUSED( role  )
 
138
   return false;
 
139
}
 
140
 
 
141
//Set the current call
 
142
void NumberCompletionModel::setCall(Call* call)
 
143
{
 
144
   if (m_pCall)
 
145
      disconnect(m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString)));
 
146
   m_pCall = call;
 
147
   if (m_pCall)
 
148
      connect(m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString)));
 
149
   setPrefix(call?call->dialNumber():QString());
 
150
}
 
151
 
 
152
void NumberCompletionModel::setPrefix(const QString& str)
 
153
{
 
154
   m_Prefix = str;
 
155
   const bool e = ((m_pCall && m_pCall->state() == Call::State::DIALING) || (!m_pCall)) && (!str.isEmpty());
 
156
   if (m_Enabled != e) {
 
157
      m_Enabled = e;
 
158
      emit enabled(e);
 
159
   }
 
160
   if (m_Enabled)
 
161
      updateModel();
 
162
   else {
 
163
      m_hNumbers.clear();
 
164
      emit layoutChanged();
 
165
   }
 
166
}
 
167
 
 
168
Call* NumberCompletionModel::call() const
 
169
{
 
170
   return m_pCall;
 
171
}
 
172
 
 
173
PhoneNumber* NumberCompletionModel::number(const QModelIndex& idx) const
 
174
{
 
175
   if (idx.isValid()) {
 
176
      return (const_cast<NumberCompletionModel*>(this)->m_hNumbers.end()-1-idx.row()).value();
 
177
   }
 
178
   return nullptr;
 
179
}
 
180
 
 
181
void NumberCompletionModel::updateModel()
 
182
{
 
183
   QSet<PhoneNumber*> numbers;
 
184
   beginResetModel();
 
185
   m_hNumbers.clear();
 
186
   if (!m_Prefix.isEmpty()) {
 
187
      locateNameRange  ( m_Prefix, numbers );
 
188
      locateNumberRange( m_Prefix, numbers );
 
189
 
 
190
      foreach(PhoneNumber* n,numbers) {
 
191
         if (m_UseUnregisteredAccount || ((n->account() && n->account()->isRegistered()) || !n->account()))
 
192
            m_hNumbers.insert(getWeight(n),n);
 
193
      }
 
194
   }
 
195
   endResetModel();
 
196
   emit layoutChanged();
 
197
}
 
198
 
 
199
void NumberCompletionModel::getRange(QMap<QString,PhoneDirectoryModel::NumberWrapper*> map, const QString& prefix, QSet<PhoneNumber*>& set) const
 
200
{
 
201
   if (prefix.isEmpty())
 
202
      return;
 
203
   QMap<QString,PhoneDirectoryModel::NumberWrapper*>::iterator iBeg = map.begin();
 
204
   QMap<QString,PhoneDirectoryModel::NumberWrapper*>::iterator iEnd = map.end  ()-1;
 
205
 
 
206
   const QString pref = prefix.toLower();
 
207
 
 
208
   const int prefixLen = pref.size();
 
209
   int size = map.size()/2;
 
210
   bool startOk(false),endOk(false);
 
211
   while (size > 1 && !(startOk&&endOk)) {
 
212
      QMap<QString,PhoneDirectoryModel::NumberWrapper*>::iterator mid;
 
213
      if (size > 7)
 
214
         mid = (iBeg+size);
 
215
      else {
 
216
         //We have to be careful with "::ceil" it may cause an overflow in some rare case
 
217
         int toAdd = size-1;
 
218
         mid = iBeg;
 
219
         while (toAdd && mid != map.end()) {
 
220
            ++mid;
 
221
            --toAdd;
 
222
         }
 
223
      }
 
224
      if (mid != map.end() && mid.key().left(prefixLen) == pref && iBeg.key().left(prefixLen) < pref) {
 
225
         //Too far, need to go back
 
226
         iBeg = mid;
 
227
         while ((iBeg-1).key().left(prefixLen) == pref && iBeg != map.begin())
 
228
            iBeg--;
 
229
         startOk = true;
 
230
      }
 
231
      else if ((!startOk) && mid != map.end() && mid.key().left(prefixLen) < pref) {
 
232
         iBeg = mid;
 
233
      }
 
234
      else if(!endOk) {
 
235
         iEnd = mid;
 
236
      }
 
237
 
 
238
      while ((iEnd).key().left(prefixLen) == pref && iEnd+1 != map.end()) {
 
239
         ++iEnd;
 
240
      }
 
241
 
 
242
      endOk = (iEnd.key().left(prefixLen) == pref);
 
243
 
 
244
      size = ::ceil(size/2.0f);
 
245
   }
 
246
 
 
247
   while (iBeg.key().left(prefixLen) != pref && iBeg != iEnd)
 
248
      ++iBeg;
 
249
 
 
250
   if (iEnd == iBeg && iBeg.key().left(prefixLen) != pref) {
 
251
      iEnd = map.end();
 
252
      iBeg = map.end();
 
253
   }
 
254
   while(iBeg != iEnd) {
 
255
      foreach(PhoneNumber* n,iBeg.value()->numbers) {
 
256
         if (n) {
 
257
            set << n;
 
258
         }
 
259
      }
 
260
      ++iBeg;
 
261
   }
 
262
}
 
263
 
 
264
void NumberCompletionModel::locateNameRange(const QString& prefix, QSet<PhoneNumber*>& set)
 
265
{
 
266
   getRange(PhoneDirectoryModel::instance()->m_lSortedNames,prefix,set);
 
267
}
 
268
 
 
269
void NumberCompletionModel::locateNumberRange(const QString& prefix, QSet<PhoneNumber*>& set)
 
270
{
 
271
   getRange(PhoneDirectoryModel::instance()->m_hSortedNumbers,prefix,set);
 
272
}
 
273
 
 
274
uint NumberCompletionModel::getWeight(PhoneNumber* number)
 
275
{
 
276
   Q_UNUSED(number)
 
277
   uint weight = 1;
 
278
   weight += (number->weekCount()+1)*150;
 
279
   weight += (number->trimCount()+1)*75 ;
 
280
   weight += (number->callCount()+1)*35 ;
 
281
   weight *= (number->uri().indexOf(m_Prefix)!= -1?3:1);
 
282
   weight *= (number->isPresent()?2:1);
 
283
   return weight;
 
284
}
 
285
 
 
286
QString NumberCompletionModel::prefix() const
 
287
{
 
288
   return m_Prefix;
 
289
}
 
290
 
 
291
void NumberCompletionModel::setUseUnregisteredAccounts(bool value)
 
292
{
 
293
   m_UseUnregisteredAccount = value;
 
294
}
 
295
 
 
296
bool NumberCompletionModel::isUsingUnregisteredAccounts()
 
297
{
 
298
   return m_UseUnregisteredAccount;
 
299
}