1
/****************************************************************************
2
* Copyright (C) 2013-2014 by Savoir-Faire Linux *
3
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
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. *
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. *
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"
21
#include <QtCore/QCoreApplication>
27
#include "phonedirectorymodel.h"
28
#include "phonenumber.h"
30
#include "numbercategory.h"
31
#include "accountlistmodel.h"
32
#include "numbercategorymodel.h"
33
#include "visitors/pixmapmanipulationvisitor.h"
35
NumberCompletionModel::NumberCompletionModel() : QAbstractTableModel(QCoreApplication::instance()),
36
m_pCall(nullptr),m_Enabled(false),m_UseUnregisteredAccount(true)
38
setObjectName("NumberCompletionModel");
41
NumberCompletionModel::~NumberCompletionModel()
46
QVariant NumberCompletionModel::data(const QModelIndex& index, int role ) const
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 ();
53
bool needAcc = (role>=100 || role == Qt::UserRole) && n->account() && n->account() != AccountListModel::instance()->currentAccount()
54
&& n->account()->alias() != "IP2IP";
56
switch (static_cast<NumberCompletionModel::Columns>(index.column())) {
57
case NumberCompletionModel::Columns::CONTENT:
63
return QString("<table><tr><td>%1</td></tr><tr><td>%2</td></tr></table>").arg(n->primaryName()).arg(n->category()->name());
65
case Qt::DecorationRole:
68
case NumberCompletionModel::Role::ALTERNATE_ACCOUNT:
71
return n->account()->alias();
74
case NumberCompletionModel::Role::FORCE_ACCOUNT:
76
case NumberCompletionModel::Role::ACCOUNT:
78
return QVariant::fromValue(const_cast<Account*>(n->account()));
82
case NumberCompletionModel::Columns::NAME:
85
return n->primaryName();
88
case NumberCompletionModel::Columns::ACCOUNT:
91
return n->account()?n->account()->id():AccountListModel::instance()->currentAccount()->id();
94
case NumberCompletionModel::Columns::WEIGHT:
104
int NumberCompletionModel::rowCount(const QModelIndex& parent ) const
106
if (parent.isValid())
108
return m_hNumbers.size();
111
int NumberCompletionModel::columnCount(const QModelIndex& parent ) const
113
if (parent.isValid())
118
Qt::ItemFlags NumberCompletionModel::flags(const QModelIndex& index ) const
120
if (!index.isValid()) return Qt::NoItemFlags;
121
return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
124
QVariant NumberCompletionModel::headerData (int section, Qt::Orientation orientation, int role) const
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];
133
bool NumberCompletionModel::setData(const QModelIndex& index, const QVariant &value, int role)
141
//Set the current call
142
void NumberCompletionModel::setCall(Call* call)
145
disconnect(m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString)));
148
connect(m_pCall,SIGNAL(dialNumberChanged(QString)),this,SLOT(setPrefix(QString)));
149
setPrefix(call?call->dialNumber():QString());
152
void NumberCompletionModel::setPrefix(const QString& str)
155
const bool e = ((m_pCall && m_pCall->state() == Call::State::DIALING) || (!m_pCall)) && (!str.isEmpty());
156
if (m_Enabled != e) {
164
emit layoutChanged();
168
Call* NumberCompletionModel::call() const
173
PhoneNumber* NumberCompletionModel::number(const QModelIndex& idx) const
176
return (const_cast<NumberCompletionModel*>(this)->m_hNumbers.end()-1-idx.row()).value();
181
void NumberCompletionModel::updateModel()
183
QSet<PhoneNumber*> numbers;
186
if (!m_Prefix.isEmpty()) {
187
locateNameRange ( m_Prefix, numbers );
188
locateNumberRange( m_Prefix, numbers );
190
foreach(PhoneNumber* n,numbers) {
191
if (m_UseUnregisteredAccount || ((n->account() && n->account()->isRegistered()) || !n->account()))
192
m_hNumbers.insert(getWeight(n),n);
196
emit layoutChanged();
199
void NumberCompletionModel::getRange(QMap<QString,PhoneDirectoryModel::NumberWrapper*> map, const QString& prefix, QSet<PhoneNumber*>& set) const
201
if (prefix.isEmpty())
203
QMap<QString,PhoneDirectoryModel::NumberWrapper*>::iterator iBeg = map.begin();
204
QMap<QString,PhoneDirectoryModel::NumberWrapper*>::iterator iEnd = map.end ()-1;
206
const QString pref = prefix.toLower();
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;
216
//We have to be careful with "::ceil" it may cause an overflow in some rare case
219
while (toAdd && mid != map.end()) {
224
if (mid != map.end() && mid.key().left(prefixLen) == pref && iBeg.key().left(prefixLen) < pref) {
225
//Too far, need to go back
227
while ((iBeg-1).key().left(prefixLen) == pref && iBeg != map.begin())
231
else if ((!startOk) && mid != map.end() && mid.key().left(prefixLen) < pref) {
238
while ((iEnd).key().left(prefixLen) == pref && iEnd+1 != map.end()) {
242
endOk = (iEnd.key().left(prefixLen) == pref);
244
size = ::ceil(size/2.0f);
247
while (iBeg.key().left(prefixLen) != pref && iBeg != iEnd)
250
if (iEnd == iBeg && iBeg.key().left(prefixLen) != pref) {
254
while(iBeg != iEnd) {
255
foreach(PhoneNumber* n,iBeg.value()->numbers) {
264
void NumberCompletionModel::locateNameRange(const QString& prefix, QSet<PhoneNumber*>& set)
266
getRange(PhoneDirectoryModel::instance()->m_lSortedNames,prefix,set);
269
void NumberCompletionModel::locateNumberRange(const QString& prefix, QSet<PhoneNumber*>& set)
271
getRange(PhoneDirectoryModel::instance()->m_hSortedNumbers,prefix,set);
274
uint NumberCompletionModel::getWeight(PhoneNumber* number)
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);
286
QString NumberCompletionModel::prefix() const
291
void NumberCompletionModel::setUseUnregisteredAccounts(bool value)
293
m_UseUnregisteredAccount = value;
296
bool NumberCompletionModel::isUsingUnregisteredAccounts()
298
return m_UseUnregisteredAccount;