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

« back to all changes in this revision

Viewing changes to kde/src/lib/historymodel.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
1
/****************************************************************************
2
 
 *   Copyright (C) 2012-2013 by Savoir-Faire Linux                          *
 
2
 *   Copyright (C) 2012-2014 by Savoir-Faire Linux                          *
3
3
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
4
4
 *                                                                          *
5
5
 *   This library is free software; you can redistribute it and/or          *
16
16
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
17
17
 ***************************************************************************/
18
18
#include "historymodel.h"
19
 
#include "callmanager_interface_singleton.h"
20
 
#include "configurationmanager_interface_singleton.h"
 
19
 
 
20
//C include
 
21
#include <time.h>
 
22
 
 
23
//SFLPhone lib
 
24
#include "dbus/callmanager.h"
 
25
#include "dbus/configurationmanager.h"
21
26
#include "call.h"
22
 
 
 
27
#include "contact.h"
 
28
#include "phonenumber.h"
 
29
#include "callmodel.h"
 
30
#include "historytimecategorymodel.h"
 
31
#include "lastusednumbermodel.h"
23
32
 
24
33
/*****************************************************************************
25
34
 *                                                                           *
27
36
 *                                                                           *
28
37
 ****************************************************************************/
29
38
 
30
 
///SortableCallSource: helper class to make sorting possible
31
 
class SortableCallSource {
32
 
public:
33
 
   SortableCallSource(Call* call=0) : count(0),callInfo(call) {}
34
 
   uint count;
35
 
   Call* callInfo;
36
 
   bool operator<(SortableCallSource other) {
37
 
      return (other.count > count);
38
 
   }
39
 
};
 
39
HistoryItemNode::HistoryItemNode(HistoryModel* m, Call* c, HistoryModel::HistoryItem* backend) :
 
40
m_pCall(c),m_pBackend(backend),m_pModel(m){
 
41
   connect(c,SIGNAL(changed()),this,SLOT(slotNumberChanged()));
 
42
}
40
43
 
41
 
inline bool operator< (const SortableCallSource & s1, const SortableCallSource & s2)
 
44
void HistoryItemNode::slotNumberChanged()
42
45
{
43
 
    return  s1.count < s2.count;
 
46
   emit changed(m_pModel->index(m_pBackend->m_Index,0,m_pModel->index(m_pBackend->m_pParent->m_AbsoluteIndex,0)));
44
47
}
45
48
 
46
49
HistoryModel* HistoryModel::m_spInstance    = nullptr;
47
50
CallMap       HistoryModel::m_sHistoryCalls          ;
48
51
 
 
52
HistoryModel::TopLevelItem::TopLevelItem(const QString& name, int index) : 
 
53
   CategorizedCompositeNode(CategorizedCompositeNode::Type::TOP_LEVEL),QObject(nullptr),m_Index(index),m_NameStr(name)
 
54
{}
 
55
 
 
56
HistoryModel::TopLevelItem::~TopLevelItem() {
 
57
   m_spInstance->m_lCategoryCounter.removeAll(this);
 
58
   while(m_lChildren.size()) {
 
59
      HistoryModel::HistoryItem* item = m_lChildren[0];
 
60
      m_lChildren.remove(0);
 
61
      delete item;
 
62
   }
 
63
}
 
64
 
 
65
QObject* HistoryModel::TopLevelItem::getSelf() const
 
66
{
 
67
   return const_cast<HistoryModel::TopLevelItem*>(this);
 
68
}
 
69
 
 
70
HistoryModel::HistoryItem::HistoryItem(Call* call) : CategorizedCompositeNode(CategorizedCompositeNode::Type::CALL),m_pCall(call)
 
71
{
 
72
   
 
73
}
 
74
 
 
75
HistoryModel::HistoryItem::~HistoryItem()
 
76
{
 
77
   delete m_pNode;
 
78
}
 
79
 
 
80
 
 
81
QObject* HistoryModel::HistoryItem::getSelf() const
 
82
{
 
83
   return const_cast<Call*>(m_pCall);
 
84
}
 
85
 
 
86
Call* HistoryModel::HistoryItem::call() const
 
87
{
 
88
   return m_pCall;
 
89
}
 
90
 
49
91
 
50
92
/*****************************************************************************
51
93
 *                                                                           *
54
96
 ****************************************************************************/
55
97
 
56
98
///Constructor
57
 
HistoryModel::HistoryModel():m_HistoryInit(false)
 
99
HistoryModel::HistoryModel():QAbstractItemModel(QCoreApplication::instance()),m_HistoryInit(false),m_Role(Call::Role::FuzzyDate),m_HaveContactModel(false)
58
100
{
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(
63
 
               hc[ CALLID_KEY          ]         ,
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     ]         ,
69
 
               hc[ STATE_KEY           ]
70
 
      );
71
 
      if (pastCall->getPeerName().isEmpty()) {
72
 
         pastCall->setPeerName("Unknown");
 
103
   beginResetModel();
 
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"));
73
109
      }
74
 
      pastCall->setRecordingPath(hc[ RECORDING_PATH_KEY ]);
75
 
      addPriv(pastCall);
 
110
      pastCall->setRecordingPath(hc[ Call::HistoryMapFields::RECORDING_PATH ]);
 
111
      add(pastCall);
76
112
   }
 
113
   endResetModel();
77
114
   m_HistoryInit = true;
 
115
   m_spInstance  = this;
 
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"   ));
 
146
   setRoleNames(roles);
78
147
} //initHistory
79
148
 
80
149
///Destructor
81
150
HistoryModel::~HistoryModel()
82
151
{
 
152
   for (int i=0; i<m_lCategoryCounter.size();i++) {
 
153
      delete m_lCategoryCounter[i];
 
154
   }
 
155
   while(m_lCategoryCounter.size()) {
 
156
      TopLevelItem* item = m_lCategoryCounter[0];
 
157
      m_lCategoryCounter.removeAt(0);
 
158
      delete item;
 
159
   }
83
160
   m_spInstance = nullptr;
84
161
}
85
162
 
86
163
///Singleton
87
 
HistoryModel* HistoryModel::self()
 
164
HistoryModel* HistoryModel::instance()
88
165
{
89
166
   if (!m_spInstance)
90
167
      m_spInstance = new HistoryModel();
97
174
 *                           History related code                            *
98
175
 *                                                                           *
99
176
 ****************************************************************************/
 
177
///Get the top level item based on a call
 
178
HistoryModel::TopLevelItem* HistoryModel::getCategory(const Call* call)
 
179
{
 
180
   TopLevelItem* category = nullptr;
 
181
   QString name;
 
182
   int index = -1;
 
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];
 
187
   }
 
188
   else {
 
189
      name = call->roleData(m_Role).toString();
 
190
      category = m_hCategoryByName[name];
 
191
   }
 
192
   if (!category) {
 
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;
 
201
//       endInsertRows();
 
202
//       emit layoutChanged();
 
203
   }
 
204
   return category;
 
205
}
100
206
 
101
207
///Add to history
102
208
void HistoryModel::add(Call* call)
103
209
{
104
 
   self()->addPriv(call);
105
 
}
106
 
 
107
 
///Add to history
108
 
void HistoryModel::addPriv(Call* call)
109
 
{
110
 
   if (call) {
111
 
      m_sHistoryCalls[call->getStartTimeStamp()] = call;
112
 
   }
 
210
   if (!call || call->state() != Call::State::OVER || !call->startTimeStamp()) {
 
211
      return;
 
212
   }
 
213
 
 
214
   if (!m_HaveContactModel && call->contactBackend()) {
 
215
      connect(((QObject*)call->contactBackend()),SIGNAL(collectionChanged()),this,SLOT(reloadCategories()));
 
216
      m_HaveContactModel = true;
 
217
   }
 
218
 
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;
 
230
 
 
231
   //Try to prevent startTimeStamp() collisions, it technically doesn't work as time_t are signed
 
232
   //we don't care
 
233
   m_sHistoryCalls[(call->startTimeStamp() << 10)+qrand()%1024] = call;
 
234
   endInsertRows();
 
235
   emit layoutChanged();
 
236
   LastUsedNumberModel::instance()->addCall(call);
114
237
   emit historyChanged();
115
238
}
116
239
 
117
 
///Return the history list
118
 
const CallMap& HistoryModel::getHistory()
119
 
{
120
 
   self();
121
 
   return m_sHistoryCalls;
122
 
}
123
 
 
124
 
///Return a list of all previous calls
125
 
const QStringList HistoryModel::getHistoryCallId()
126
 
{
127
 
   self();
128
 
   QStringList toReturn;
 
240
///Set if the history has a limit
 
241
void HistoryModel::setHistoryLimited(bool isLimited)
 
242
{
 
243
   if (!isLimited)
 
244
      DBus::ConfigurationManager::instance().setHistoryLimit(0);
 
245
}
 
246
 
 
247
///Set the number of days before history items are discarded
 
248
void HistoryModel::setHistoryLimit(int numberOfDays)
 
249
{
 
250
   DBus::ConfigurationManager::instance().setHistoryLimit(numberOfDays);
 
251
}
 
252
 
 
253
///Is history items are being deleted after "historyLimit()" days
 
254
bool HistoryModel::isHistoryLimited() const
 
255
{
 
256
   return DBus::ConfigurationManager::instance().getHistoryLimit() != 0;
 
257
}
 
258
 
 
259
///Number of days before items are discarded (0 = never)
 
260
int HistoryModel::historyLimit() const
 
261
{
 
262
   return DBus::ConfigurationManager::instance().getHistoryLimit();
 
263
}
 
264
 
 
265
 
 
266
/*****************************************************************************
 
267
 *                                                                           *
 
268
 *                              Model related                                *
 
269
 *                                                                           *
 
270
 ****************************************************************************/
 
271
 
 
272
void HistoryModel::reloadCategories()
 
273
{
 
274
   if (!m_HistoryInit)
 
275
      return;
 
276
   beginResetModel();
 
277
   m_hCategories.clear();
 
278
   m_hCategoryByName.clear();
 
279
   foreach(TopLevelItem* item, m_lCategoryCounter) {
 
280
      delete item;
 
281
   }
 
282
   m_lCategoryCounter.clear();
 
283
   m_isContactDateInit = false;
129
284
   foreach(Call* call, m_sHistoryCalls) {
130
 
      toReturn << call->getCallId();
131
 
   }
132
 
   return toReturn;
133
 
}
134
 
 
135
 
///Sort all history call by popularity and return the result (most popular first)
136
 
const QStringList HistoryModel::getNumbersByPopularity()
137
 
{
138
 
   self();
139
 
   QHash<QString,SortableCallSource*> hc;
140
 
   foreach (Call* call, getHistory()) {
141
 
      if (!hc[call->getPeerPhoneNumber()]) {
142
 
         hc[call->getPeerPhoneNumber()] = new SortableCallSource(call);
143
 
      }
144
 
      hc[call->getPeerPhoneNumber()]->count++;
145
 
   }
146
 
   QList<SortableCallSource> userList;
147
 
   foreach (SortableCallSource* i,hc) {
148
 
      userList << *i;
149
 
   }
150
 
   qSort(userList);
151
 
   QStringList cl;
152
 
   for (int i=userList.size()-1;i >=0 ;i--) {
153
 
      cl << userList[i].callInfo->getPeerPhoneNumber();
154
 
   }
155
 
   foreach (SortableCallSource* i,hc) {
156
 
      delete i;
157
 
   }
158
 
 
159
 
   return cl;
160
 
} //getNumbersByPopularity
 
285
      TopLevelItem* category = getCategory(call);
 
286
      if (category) {
 
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;
 
293
      }
 
294
      else
 
295
         qDebug() << "ERROR count";
 
296
   }
 
297
   endResetModel();
 
298
   emit layoutAboutToBeChanged();
 
299
   emit layoutChanged();
 
300
   emit dataChanged(index(0,0),index(rowCount()-1,0));
 
301
}
 
302
 
 
303
void HistoryModel::slotChanged(const QModelIndex& idx)
 
304
{
 
305
   emit dataChanged(idx,idx);
 
306
}
 
307
 
 
308
bool HistoryModel::setData( const QModelIndex& idx, const QVariant &value, int role)
 
309
{
 
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);
 
315
      }
 
316
   }
 
317
   return false;
 
318
}
 
319
 
 
320
QVariant HistoryModel::data( const QModelIndex& idx, int role) const
 
321
{
 
322
   if (!idx.isValid())
 
323
      return QVariant();
 
324
 
 
325
   CategorizedCompositeNode* modelItem = static_cast<CategorizedCompositeNode*>(idx.internalPointer());
 
326
   switch (modelItem->type()) {
 
327
      case CategorizedCompositeNode::Type::TOP_LEVEL:
 
328
      switch (role) {
 
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;
 
334
         default:
 
335
            break;
 
336
      }
 
337
      break;
 
338
   case CategorizedCompositeNode::Type::CALL:
 
339
      if (role == Call::Role::DropState)
 
340
         return QVariant(modelItem->dropState());
 
341
      else {
 
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);
 
346
      }
 
347
      break;
 
348
   case CategorizedCompositeNode::Type::NUMBER:
 
349
   case CategorizedCompositeNode::Type::BOOKMARK:
 
350
   case CategorizedCompositeNode::Type::CONTACT:
 
351
   default:
 
352
      break;
 
353
   };
 
354
   return QVariant();
 
355
}
 
356
 
 
357
QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
 
358
{
 
359
   Q_UNUSED(section)
 
360
   if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
 
361
      return QVariant(tr("History"));
 
362
   if (role == Qt::InitialSortOrderRole)
 
363
      return QVariant(Qt::DescendingOrder);
 
364
   return QVariant();
 
365
}
 
366
 
 
367
int HistoryModel::rowCount( const QModelIndex& parentIdx ) const
 
368
{
 
369
   if ((!parentIdx.isValid()) || (!parentIdx.internalPointer())) {
 
370
      return m_lCategoryCounter.size();
 
371
   }
 
372
   else {
 
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:
 
381
         default:
 
382
            return 0;
 
383
      };
 
384
   }
 
385
}
 
386
 
 
387
Qt::ItemFlags HistoryModel::flags( const QModelIndex& idx ) const
 
388
{
 
389
   if (!idx.isValid())
 
390
      return Qt::NoItemFlags;
 
391
   return Qt::ItemIsEnabled | Qt::ItemIsSelectable | (idx.parent().isValid()?Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled:Qt::ItemIsEnabled);
 
392
}
 
393
 
 
394
int HistoryModel::columnCount ( const QModelIndex& parentIdx) const
 
395
{
 
396
   Q_UNUSED(parentIdx)
 
397
   return 1;
 
398
}
 
399
 
 
400
QModelIndex HistoryModel::parent( const QModelIndex& idx) const
 
401
{
 
402
   if (!idx.isValid() || !idx.internalPointer()) {
 
403
      return QModelIndex();
 
404
   }
 
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);
 
409
      if (tli)
 
410
         return HistoryModel::index(tli->modelRow,0);
 
411
   }
 
412
   return QModelIndex();
 
413
}
 
414
 
 
415
QModelIndex HistoryModel::index( int row, int column, const QModelIndex& parentIdx) const
 
416
{
 
417
   if (!parentIdx.isValid()) {
 
418
      if (row >= 0 && m_lCategoryCounter.size() > row) {
 
419
         return createIndex(row,column,(void*)m_lCategoryCounter[row]);
 
420
      }
 
421
   }
 
422
   else {
 
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]));
 
428
            break;
 
429
         case CategorizedCompositeNode::Type::CALL:
 
430
         case CategorizedCompositeNode::Type::NUMBER:
 
431
         case CategorizedCompositeNode::Type::BOOKMARK:
 
432
         case CategorizedCompositeNode::Type::CONTACT:
 
433
            break;
 
434
      };
 
435
   }
 
436
   return QModelIndex();
 
437
}
 
438
 
 
439
///Called when dynamically adding calls, otherwise the proxy filter will segfault
 
440
bool HistoryModel::insertRows( int row, int count, const QModelIndex & parent)
 
441
{
 
442
   if (parent.isValid()) {
 
443
      beginInsertRows(parent,row,row+count-1);
 
444
      endInsertRows();
 
445
      return true;
 
446
   }
 
447
   return false;
 
448
}
 
449
 
 
450
QStringList HistoryModel::mimeTypes() const
 
451
{
 
452
   return m_lMimes;
 
453
}
 
454
 
 
455
QMimeData* HistoryModel::mimeData(const QModelIndexList &indexes) const
 
456
{
 
457
   QMimeData *mimeData2 = new QMimeData();
 
458
   foreach (const QModelIndex &idx, indexes) {
 
459
      if (idx.isValid()) {
 
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());
 
467
         return mimeData2;
 
468
      }
 
469
   }
 
470
   return mimeData2;
 
471
}
 
472
 
 
473
 
 
474
bool HistoryModel::dropMimeData(const QMimeData *mime, Qt::DropAction action, int row, int column, const QModelIndex &parentIdx)
 
475
{
 
476
   Q_UNUSED(row)
 
477
   Q_UNUSED(column)
 
478
   Q_UNUSED(action)
 
479
   setData(parentIdx,-1,Call::Role::DropState);
 
480
   QByteArray encodedPhoneNumber = mime->data( MIME_PHONENUMBER );
 
481
   QByteArray encodedContact     = mime->data( MIME_CONTACT     );
 
482
 
 
483
   if (parentIdx.isValid() && mime->hasFormat( MIME_CALLID)) {
 
484
      QByteArray encodedCallId      = mime->data( MIME_CALLID      );
 
485
      Call* call = CallModel::instance()->getCall(encodedCallId);
 
486
      if (call) {
 
487
         const QModelIndex& idx = index(row,column,parentIdx);
 
488
         if (idx.isValid()) {
 
489
            const Call* target = (Call*)((CategorizedCompositeNode*)(idx.internalPointer()))->getSelf();
 
490
            if (target) {
 
491
               CallModel::instance()->transfer(call,target->peerPhoneNumber());
 
492
               return true;
 
493
            }
 
494
         }
 
495
      }
 
496
   }
 
497
   return false;
 
498
}
 
499
 
 
500
///Return valid payload types
 
501
int HistoryModel::acceptedPayloadTypes()
 
502
{
 
503
   return CallModel::DropPayloadType::CALL;
 
504
}
 
505
 
 
506
void HistoryModel::setCategoryRole(Call::Role role) 
 
507
{
 
508
   if (m_Role != role) {
 
509
      m_Role = role;
 
510
      reloadCategories();
 
511
   }
 
512
}