54
96
****************************************************************************/
57
HistoryModel::HistoryModel():m_HistoryInit(false)
99
HistoryModel::HistoryModel():QAbstractItemModel(QCoreApplication::instance()),m_HistoryInit(false),m_Role(Call::Role::FuzzyDate),m_HaveContactModel(false)
59
ConfigurationManagerInterface& configurationManager = ConfigurationManagerInterfaceSingleton::getInstance();
101
ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance();
60
102
const QVector< QMap<QString, QString> > history = configurationManager.getHistory();
61
foreach (const MapStringString& hc, history) {
62
Call* pastCall = Call::buildHistoryCall(
64
hc[ TIMESTAMP_START_KEY ].toUInt(),
65
hc[ TIMESTAMP_STOP_KEY ].toUInt(),
66
hc[ ACCOUNT_ID_KEY ] ,
67
hc[ DISPLAY_NAME_KEY ] ,
68
hc[ PEER_NUMBER_KEY ] ,
71
if (pastCall->getPeerName().isEmpty()) {
72
pastCall->setPeerName("Unknown");
104
for(int i = history.size()-1;i>=0;i--) {
105
const MapStringString& hc = history[i];
106
Call* pastCall = Call::buildHistoryCall(hc);
107
if (pastCall->peerName().isEmpty()) {
108
pastCall->setPeerName(tr("Unknown"));
74
pastCall->setRecordingPath(hc[ RECORDING_PATH_KEY ]);
110
pastCall->setRecordingPath(hc[ Call::HistoryMapFields::RECORDING_PATH ]);
77
114
m_HistoryInit = true;
116
// reloadCategories();
117
m_lMimes << MIME_PLAIN_TEXT << MIME_PHONENUMBER << MIME_HISTORYID;
118
QHash<int, QByteArray> roles = roleNames();
119
roles.insert(Call::Role::Name ,QByteArray("name" ));
120
roles.insert(Call::Role::Number ,QByteArray("number" ));
121
roles.insert(Call::Role::Direction2 ,QByteArray("direction" ));
122
roles.insert(Call::Role::Date ,QByteArray("date" ));
123
roles.insert(Call::Role::Length ,QByteArray("length" ));
124
roles.insert(Call::Role::FormattedDate ,QByteArray("formattedDate" ));
125
roles.insert(Call::Role::HasRecording ,QByteArray("hasRecording" ));
126
roles.insert(Call::Role::Historystate ,QByteArray("historyState" ));
127
roles.insert(Call::Role::Filter ,QByteArray("filter" ));
128
roles.insert(Call::Role::FuzzyDate ,QByteArray("fuzzyDate" ));
129
roles.insert(Call::Role::IsBookmark ,QByteArray("isBookmark" ));
130
roles.insert(Call::Role::Security ,QByteArray("security" ));
131
roles.insert(Call::Role::Department ,QByteArray("department" ));
132
roles.insert(Call::Role::Email ,QByteArray("email" ));
133
roles.insert(Call::Role::Organisation ,QByteArray("organisation" ));
134
roles.insert(Call::Role::Codec ,QByteArray("codec" ));
135
roles.insert(Call::Role::IsConference ,QByteArray("isConference" ));
136
roles.insert(Call::Role::Object ,QByteArray("object" ));
137
roles.insert(Call::Role::PhotoPtr ,QByteArray("photoPtr" ));
138
roles.insert(Call::Role::CallState ,QByteArray("callState" ));
139
roles.insert(Call::Role::Id ,QByteArray("id" ));
140
roles.insert(Call::Role::StartTime ,QByteArray("startTime" ));
141
roles.insert(Call::Role::StopTime ,QByteArray("stopTime" ));
142
roles.insert(Call::Role::DropState ,QByteArray("dropState" ));
143
roles.insert(Call::Role::DTMFAnimState ,QByteArray("dTMFAnimState" ));
144
roles.insert(Call::Role::LastDTMFidx ,QByteArray("lastDTMFidx" ));
145
roles.insert(Call::Role::IsRecording ,QByteArray("isRecording" ));
81
150
HistoryModel::~HistoryModel()
152
for (int i=0; i<m_lCategoryCounter.size();i++) {
153
delete m_lCategoryCounter[i];
155
while(m_lCategoryCounter.size()) {
156
TopLevelItem* item = m_lCategoryCounter[0];
157
m_lCategoryCounter.removeAt(0);
83
160
m_spInstance = nullptr;
87
HistoryModel* HistoryModel::self()
164
HistoryModel* HistoryModel::instance()
89
166
if (!m_spInstance)
90
167
m_spInstance = new HistoryModel();
97
174
* History related code *
99
176
****************************************************************************/
177
///Get the top level item based on a call
178
HistoryModel::TopLevelItem* HistoryModel::getCategory(const Call* call)
180
TopLevelItem* category = nullptr;
183
if (m_Role == Call::Role::FuzzyDate) {
184
index = call->roleData(Call::Role::FuzzyDate).toInt();
185
name = HistoryTimeCategoryModel::indexToName(index);
186
category = m_hCategories[index];
189
name = call->roleData(m_Role).toString();
190
category = m_hCategoryByName[name];
193
category = new TopLevelItem(name,index);
194
category->modelRow = m_lCategoryCounter.size();
195
// emit layoutAboutToBeChanged(); //Not necessary
196
// beginInsertRows(QModelIndex(),m_lCategoryCounter.size(),m_lCategoryCounter.size());
197
category->m_AbsoluteIndex = m_lCategoryCounter.size();
198
m_lCategoryCounter << category;
199
m_hCategories [index] = category;
200
m_hCategoryByName[name ] = category;
202
// emit layoutChanged();
101
207
///Add to history
102
208
void HistoryModel::add(Call* call)
104
self()->addPriv(call);
108
void HistoryModel::addPriv(Call* call)
111
m_sHistoryCalls[call->getStartTimeStamp()] = call;
210
if (!call || call->state() != Call::State::OVER || !call->startTimeStamp()) {
214
if (!m_HaveContactModel && call->contactBackend()) {
215
connect(((QObject*)call->contactBackend()),SIGNAL(collectionChanged()),this,SLOT(reloadCategories()));
216
m_HaveContactModel = true;
113
219
emit newHistoryCall(call);
220
emit layoutAboutToBeChanged();
221
TopLevelItem* tl = getCategory(call);
222
const QModelIndex& parentIdx = index(tl->modelRow,0);
223
beginInsertRows(parentIdx,tl->m_lChildren.size(),tl->m_lChildren.size());
224
HistoryItem* item = new HistoryItem(call);
225
item->m_pParent = tl;
226
item->m_pNode = new HistoryItemNode(this,call,item);
227
connect(item->m_pNode,SIGNAL(changed(QModelIndex)),this,SLOT(slotChanged(QModelIndex)));
228
item->m_Index = tl->m_lChildren.size();
229
tl->m_lChildren << item;
231
//Try to prevent startTimeStamp() collisions, it technically doesn't work as time_t are signed
233
m_sHistoryCalls[(call->startTimeStamp() << 10)+qrand()%1024] = call;
235
emit layoutChanged();
236
LastUsedNumberModel::instance()->addCall(call);
114
237
emit historyChanged();
117
///Return the history list
118
const CallMap& HistoryModel::getHistory()
121
return m_sHistoryCalls;
124
///Return a list of all previous calls
125
const QStringList HistoryModel::getHistoryCallId()
128
QStringList toReturn;
240
///Set if the history has a limit
241
void HistoryModel::setHistoryLimited(bool isLimited)
244
DBus::ConfigurationManager::instance().setHistoryLimit(0);
247
///Set the number of days before history items are discarded
248
void HistoryModel::setHistoryLimit(int numberOfDays)
250
DBus::ConfigurationManager::instance().setHistoryLimit(numberOfDays);
253
///Is history items are being deleted after "historyLimit()" days
254
bool HistoryModel::isHistoryLimited() const
256
return DBus::ConfigurationManager::instance().getHistoryLimit() != 0;
259
///Number of days before items are discarded (0 = never)
260
int HistoryModel::historyLimit() const
262
return DBus::ConfigurationManager::instance().getHistoryLimit();
266
/*****************************************************************************
270
****************************************************************************/
272
void HistoryModel::reloadCategories()
277
m_hCategories.clear();
278
m_hCategoryByName.clear();
279
foreach(TopLevelItem* item, m_lCategoryCounter) {
282
m_lCategoryCounter.clear();
283
m_isContactDateInit = false;
129
284
foreach(Call* call, m_sHistoryCalls) {
130
toReturn << call->getCallId();
135
///Sort all history call by popularity and return the result (most popular first)
136
const QStringList HistoryModel::getNumbersByPopularity()
139
QHash<QString,SortableCallSource*> hc;
140
foreach (Call* call, getHistory()) {
141
if (!hc[call->getPeerPhoneNumber()]) {
142
hc[call->getPeerPhoneNumber()] = new SortableCallSource(call);
144
hc[call->getPeerPhoneNumber()]->count++;
146
QList<SortableCallSource> userList;
147
foreach (SortableCallSource* i,hc) {
152
for (int i=userList.size()-1;i >=0 ;i--) {
153
cl << userList[i].callInfo->getPeerPhoneNumber();
155
foreach (SortableCallSource* i,hc) {
160
} //getNumbersByPopularity
285
TopLevelItem* category = getCategory(call);
287
HistoryItem* item = new HistoryItem(call);
288
item->m_Index = category->m_lChildren.size();
289
item->m_pNode = new HistoryItemNode(this,call,item);
290
connect(item->m_pNode,SIGNAL(changed(QModelIndex)),this,SLOT(slotChanged(QModelIndex)));
291
item->m_pParent = category;
292
category->m_lChildren << item;
295
qDebug() << "ERROR count";
298
emit layoutAboutToBeChanged();
299
emit layoutChanged();
300
emit dataChanged(index(0,0),index(rowCount()-1,0));
303
void HistoryModel::slotChanged(const QModelIndex& idx)
305
emit dataChanged(idx,idx);
308
bool HistoryModel::setData( const QModelIndex& idx, const QVariant &value, int role)
310
if (idx.isValid() && idx.parent().isValid()) {
311
CategorizedCompositeNode* modelItem = (CategorizedCompositeNode*)idx.internalPointer();
312
if (role == Call::Role::DropState) {
313
modelItem->setDropState(value.toInt());
314
emit dataChanged(idx, idx);
320
QVariant HistoryModel::data( const QModelIndex& idx, int role) const
325
CategorizedCompositeNode* modelItem = static_cast<CategorizedCompositeNode*>(idx.internalPointer());
326
switch (modelItem->type()) {
327
case CategorizedCompositeNode::Type::TOP_LEVEL:
329
case Qt::DisplayRole:
330
return static_cast<TopLevelItem*>(modelItem)->m_NameStr;
331
case Call::Role::FuzzyDate:
332
case Call::Role::Date:
333
return m_lCategoryCounter.size() - static_cast<TopLevelItem*>(modelItem)->m_Index;
338
case CategorizedCompositeNode::Type::CALL:
339
if (role == Call::Role::DropState)
340
return QVariant(modelItem->dropState());
342
const int parRow = idx.parent().row();
343
const TopLevelItem* parTli = m_lCategoryCounter[parRow];
344
if (m_lCategoryCounter.size() > parRow && parRow >= 0 && parTli && parTli->m_lChildren.size() > idx.row())
345
return parTli->m_lChildren[idx.row()]->call()->roleData((Call::Role)role);
348
case CategorizedCompositeNode::Type::NUMBER:
349
case CategorizedCompositeNode::Type::BOOKMARK:
350
case CategorizedCompositeNode::Type::CONTACT:
357
QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
360
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
361
return QVariant(tr("History"));
362
if (role == Qt::InitialSortOrderRole)
363
return QVariant(Qt::DescendingOrder);
367
int HistoryModel::rowCount( const QModelIndex& parentIdx ) const
369
if ((!parentIdx.isValid()) || (!parentIdx.internalPointer())) {
370
return m_lCategoryCounter.size();
373
CategorizedCompositeNode* node = static_cast<CategorizedCompositeNode*>(parentIdx.internalPointer());
374
switch(node->type()) {
375
case CategorizedCompositeNode::Type::TOP_LEVEL:
376
return ((TopLevelItem*)node)->m_lChildren.size();
377
case CategorizedCompositeNode::Type::CALL:
378
case CategorizedCompositeNode::Type::NUMBER:
379
case CategorizedCompositeNode::Type::BOOKMARK:
380
case CategorizedCompositeNode::Type::CONTACT:
387
Qt::ItemFlags HistoryModel::flags( const QModelIndex& idx ) const
390
return Qt::NoItemFlags;
391
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | (idx.parent().isValid()?Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled:Qt::ItemIsEnabled);
394
int HistoryModel::columnCount ( const QModelIndex& parentIdx) const
400
QModelIndex HistoryModel::parent( const QModelIndex& idx) const
402
if (!idx.isValid() || !idx.internalPointer()) {
403
return QModelIndex();
405
CategorizedCompositeNode* modelItem = static_cast<CategorizedCompositeNode*>(idx.internalPointer());
406
if (modelItem && modelItem->type() == CategorizedCompositeNode::Type::CALL) {
407
const Call* call = (Call*)((CategorizedCompositeNode*)(idx.internalPointer()))->getSelf();
408
TopLevelItem* tli = const_cast<HistoryModel*>(this)->getCategory(call);
410
return HistoryModel::index(tli->modelRow,0);
412
return QModelIndex();
415
QModelIndex HistoryModel::index( int row, int column, const QModelIndex& parentIdx) const
417
if (!parentIdx.isValid()) {
418
if (row >= 0 && m_lCategoryCounter.size() > row) {
419
return createIndex(row,column,(void*)m_lCategoryCounter[row]);
423
CategorizedCompositeNode* node = static_cast<CategorizedCompositeNode*>(parentIdx.internalPointer());
424
switch(node->type()) {
425
case CategorizedCompositeNode::Type::TOP_LEVEL:
426
if (((TopLevelItem*)node)->m_lChildren.size() > row)
427
return createIndex(row,column,(void*)static_cast<CategorizedCompositeNode*>(((TopLevelItem*)node)->m_lChildren[row]));
429
case CategorizedCompositeNode::Type::CALL:
430
case CategorizedCompositeNode::Type::NUMBER:
431
case CategorizedCompositeNode::Type::BOOKMARK:
432
case CategorizedCompositeNode::Type::CONTACT:
436
return QModelIndex();
439
///Called when dynamically adding calls, otherwise the proxy filter will segfault
440
bool HistoryModel::insertRows( int row, int count, const QModelIndex & parent)
442
if (parent.isValid()) {
443
beginInsertRows(parent,row,row+count-1);
450
QStringList HistoryModel::mimeTypes() const
455
QMimeData* HistoryModel::mimeData(const QModelIndexList &indexes) const
457
QMimeData *mimeData2 = new QMimeData();
458
foreach (const QModelIndex &idx, indexes) {
460
const QString text = data(idx, Call::Role::Number).toString();
461
mimeData2->setData(MIME_PLAIN_TEXT , text.toUtf8());
462
const Call* call = (Call*)((CategorizedCompositeNode*)(idx.internalPointer()))->getSelf();
463
mimeData2->setData(MIME_PHONENUMBER, call->peerPhoneNumber()->toHash().toUtf8());
464
CategorizedCompositeNode* node = static_cast<CategorizedCompositeNode*>(idx.internalPointer());
465
if (node->type() == CategorizedCompositeNode::Type::CALL)
466
mimeData2->setData(MIME_HISTORYID , static_cast<Call*>(node->getSelf())->id().toUtf8());
474
bool HistoryModel::dropMimeData(const QMimeData *mime, Qt::DropAction action, int row, int column, const QModelIndex &parentIdx)
479
setData(parentIdx,-1,Call::Role::DropState);
480
QByteArray encodedPhoneNumber = mime->data( MIME_PHONENUMBER );
481
QByteArray encodedContact = mime->data( MIME_CONTACT );
483
if (parentIdx.isValid() && mime->hasFormat( MIME_CALLID)) {
484
QByteArray encodedCallId = mime->data( MIME_CALLID );
485
Call* call = CallModel::instance()->getCall(encodedCallId);
487
const QModelIndex& idx = index(row,column,parentIdx);
489
const Call* target = (Call*)((CategorizedCompositeNode*)(idx.internalPointer()))->getSelf();
491
CallModel::instance()->transfer(call,target->peerPhoneNumber());
500
///Return valid payload types
501
int HistoryModel::acceptedPayloadTypes()
503
return CallModel::DropPayloadType::CALL;
506
void HistoryModel::setCategoryRole(Call::Role role)
508
if (m_Role != role) {