1
/****************************************************************************
2
* Copyright (C) 2009-2013 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
***************************************************************************/
20
#include <QtCore/QHash>
21
#include <QtCore/QDebug>
22
#include <QtGui/QDragEnterEvent>
26
#include "accountlist.h"
27
#include "dbus/metatypes.h"
28
#include "callmanager_interface_singleton.h"
29
#include "configurationmanager_interface_singleton.h"
30
#include "instance_interface_singleton.h"
31
#include "sflphone_const.h"
33
#include "contactbackend.h"
39
#define CALLMODEL_TEMPLATE template<typename CallWidget, typename Index>
40
#define CALLMODEL_T CallModel<CallWidget,Index>
43
CALLMODEL_TEMPLATE bool CALLMODEL_T::m_sInstanceInit = false ;
44
CALLMODEL_TEMPLATE bool CALLMODEL_T::m_sCallInit = false ;
45
CALLMODEL_TEMPLATE CallMap CALLMODEL_T::m_lConfList = CallMap() ;
47
CALLMODEL_TEMPLATE typename CALLMODEL_T::InternalCall CALLMODEL_T::m_sPrivateCallList_call ;
48
CALLMODEL_TEMPLATE typename CALLMODEL_T::InternalCallId CALLMODEL_T::m_sPrivateCallList_callId ;
49
CALLMODEL_TEMPLATE typename CALLMODEL_T::InternalIndex CALLMODEL_T::m_sPrivateCallList_index ;
50
CALLMODEL_TEMPLATE typename CALLMODEL_T::InternalWidget CALLMODEL_T::m_sPrivateCallList_widget ;
52
/*****************************************************************************
56
****************************************************************************/
58
///Retrieve current and older calls from the daemon, fill history and the calls TreeView and enable drag n' drop
59
CALLMODEL_TEMPLATE CALLMODEL_T::CallModel() : CallModelBase(0)
65
CALLMODEL_TEMPLATE void CALLMODEL_T::destroy()
67
foreach (Call* call, m_sPrivateCallList_call.keys()) {
70
foreach (InternalStruct* s, m_sPrivateCallList_call.values()) {
73
m_sPrivateCallList_call.clear ();
74
m_sPrivateCallList_callId.clear();
75
m_sPrivateCallList_widget.clear();
76
m_sPrivateCallList_index.clear ();
80
CALLMODEL_TEMPLATE CALLMODEL_T::~CallModel()
85
///Open the connection to the daemon and register this client
86
CALLMODEL_TEMPLATE bool CALLMODEL_T::init()
90
m_sInstanceInit = true;
95
///@warning This solution wont scale to multiple call or history model implementation. Some static addCall + foreach for each call would be needed if this case ever become unavoidable
96
CALLMODEL_TEMPLATE bool CALLMODEL_T::initCall()
99
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
100
const QStringList callList = callManager.getCallList();
101
foreach (const QString& callId, callList) {
102
Call* tmpCall = Call::buildExistingCall(callId);
103
m_sActiveCalls[tmpCall->getCallId()] = tmpCall;
107
const QStringList confList = callManager.getConferenceList();
108
foreach (const QString& confId, confList) {
109
CallModelBase::addConferenceS(addConference(confId));
117
/*****************************************************************************
119
* Access related functions *
121
****************************************************************************/
123
///Return the active call count
124
CALLMODEL_TEMPLATE int CALLMODEL_T::size()
126
return m_sActiveCalls.size();
129
///Return a call corresponding to this ID or NULL
130
CALLMODEL_TEMPLATE Call* CALLMODEL_T::findCallByCallId(const QString& callId)
132
return m_sActiveCalls[callId];
135
///Return the action call list
136
CALLMODEL_TEMPLATE CallList CALLMODEL_T::getCallList()
139
foreach(Call* call, m_sActiveCalls) {
140
if (dynamic_cast<Call*>(call) && call->getState() != CALL_STATE_OVER) //Prevent a race
141
callList.push_back(call);
146
///Return all conferences
147
CALLMODEL_TEMPLATE CallList CALLMODEL_T::getConferenceList()
151
//That way it can not be invalid
152
const QStringList confListS = CallManagerInterfaceSingleton::getInstance().getConferenceList();
153
foreach (const QString& confId, confListS) {
154
if (m_lConfList[confId] != nullptr)
155
confList << m_lConfList[confId];
157
confList << addConference(confId);
163
/*****************************************************************************
165
* Call related code *
167
****************************************************************************/
169
///Add a call in the model structure, the call must exist before being added to the model
170
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addCall(Call* call, Call* parent)
174
return new Call("",""); //Invalid, but better than managing NULL everywhere
176
InternalStruct* aNewStruct = new InternalStruct;
177
aNewStruct->call_real = call;
178
aNewStruct->conference = false;
180
m_sPrivateCallList_call [ call ] = aNewStruct;
181
m_sPrivateCallList_callId[ call->getCallId() ] = aNewStruct;
183
//setCurrentItem(callItem);
184
CallModelBase::addCall(call,parent);
188
///Common set of instruction shared by all call adder
189
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addCallCommon(Call* call)
191
m_sActiveCalls[call->getCallId()] = call;
196
///Create a new dialing call from peer name and the account ID
197
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addDialingCall(const QString& peerName, Account* account)
199
Account* acc = (account)?account:AccountList::getCurrentAccount();
201
Call* call = Call::buildDialingCall(generateCallId(), peerName, acc->getAccountId());
202
return addCallCommon(call);
209
///Create a new incoming call when the daemon is being called
210
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addIncomingCall(const QString& callId)
212
Call* call = Call::buildIncomingCall(callId);
213
Call* call2 = addCallCommon(call);
214
//Call without account is not possible
215
if (dynamic_cast<Account*>(call2->getAccount())) {
216
if (call2 && call2->getAccount()->isAutoAnswer()) {
217
call2->actionPerformed(CALL_ACTION_ACCEPT);
221
qDebug() << "Incoming call from an invalid account";
222
throw "Invalid account";
227
///Create a ringing call
228
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addRingingCall(const QString& callId)
230
Call* call = Call::buildRingingCall(callId);
231
return addCallCommon(call);
234
///Generate a new random call unique identifier (callId)
235
CALLMODEL_TEMPLATE QString CALLMODEL_T::generateCallId()
238
return QString::number(id);
241
///Remove a call and update the internal structure
242
CALLMODEL_TEMPLATE void CALLMODEL_T::removeCall(Call* call)
244
InternalStruct* internal = m_sPrivateCallList_call[call];
247
qDebug() << "Cannot remove call: call not found";
251
if (m_sPrivateCallList_call[call] != nullptr) {
252
m_sPrivateCallList_call.remove(call);
255
if (m_sPrivateCallList_callId[m_sPrivateCallList_callId.key(internal)] == internal) {
256
m_sPrivateCallList_callId.remove(m_sPrivateCallList_callId.key(internal));
259
if (m_sPrivateCallList_widget[m_sPrivateCallList_widget.key(internal)] == internal) {
260
m_sPrivateCallList_widget.remove(m_sPrivateCallList_widget.key(internal));
263
if (m_sPrivateCallList_index[m_sPrivateCallList_index.key(internal)] == internal) {
264
m_sPrivateCallList_index.remove(m_sPrivateCallList_index.key(internal));
268
///Transfer "toTransfer" to "target" and wait to see it it succeeded
269
CALLMODEL_TEMPLATE void CALLMODEL_T::attendedTransfer(Call* toTransfer, Call* target)
271
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
272
Q_NOREPLY callManager.attendedTransfer(toTransfer->getCallId(),target->getCallId());
274
//TODO [Daemon] Implement this correctly
275
toTransfer->changeCurrentState(CALL_STATE_OVER);
276
target->changeCurrentState(CALL_STATE_OVER);
279
///Transfer this call to "target" number
280
CALLMODEL_TEMPLATE void CALLMODEL_T::transfer(Call* toTransfer, QString target)
282
qDebug() << "Transferring call " << toTransfer->getCallId() << "to" << target;
283
toTransfer->setTransferNumber ( target );
284
toTransfer->changeCurrentState( CALL_STATE_TRANSFERRED );
285
toTransfer->actionPerformed ( CALL_ACTION_TRANSFER );
286
toTransfer->changeCurrentState( CALL_STATE_OVER );
289
/*****************************************************************************
291
* Conference related code *
293
****************************************************************************/
295
///Add a new conference, get the call list and update the interface as needed
296
CALLMODEL_TEMPLATE Call* CALLMODEL_T::addConference(const QString & confID)
298
qDebug() << "Notified of a new conference " << confID;
299
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
300
const QStringList callList = callManager.getParticipantList(confID);
301
qDebug() << "Paticiapants are:" << callList;
303
if (!callList.size()) {
304
qDebug() << "This conference (" + confID + ") contain no call";
308
if (!m_sPrivateCallList_callId[callList[0]]) {
309
qDebug() << "Invalid call";
313
Call* newConf = nullptr;
314
if (m_sPrivateCallList_callId[callList[0]]->call_real->getAccount())
315
newConf = new Call(confID, m_sPrivateCallList_callId[callList[0]]->call_real->getAccount()->getAccountId());
318
InternalStruct* aNewStruct = new InternalStruct;
319
aNewStruct->call_real = newConf;
320
aNewStruct->conference = true;
322
m_sPrivateCallList_call[newConf] = aNewStruct;
323
m_sPrivateCallList_callId[confID] = aNewStruct;
325
m_lConfList[newConf->getConfId()] = newConf ;
330
///Join two call to create a conference, the conference will be created later (see addConference)
331
CALLMODEL_TEMPLATE bool CALLMODEL_T::createConferenceFromCall(Call* call1, Call* call2)
333
qDebug() << "Joining call: " << call1->getCallId() << " and " << call2->getCallId();
334
CallManagerInterface &callManager = CallManagerInterfaceSingleton::getInstance();
335
Q_NOREPLY callManager.joinParticipant(call1->getCallId(),call2->getCallId());
337
} //createConferenceFromCall
339
///Add a new participant to a conference
340
CALLMODEL_TEMPLATE bool CALLMODEL_T::addParticipant(Call* call2, Call* conference)
342
if (conference->isConference()) {
343
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
344
Q_NOREPLY callManager.addParticipant(call2->getCallId(), conference->getConfId());
348
qDebug() << "This is not a conference";
353
///Remove a participant from a conference
354
CALLMODEL_TEMPLATE bool CALLMODEL_T::detachParticipant(Call* call)
356
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
357
Q_NOREPLY callManager.detachParticipant(call->getCallId());
361
///Merge two conferences
362
CALLMODEL_TEMPLATE bool CALLMODEL_T::mergeConferences(Call* conf1, Call* conf2)
364
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
365
Q_NOREPLY callManager.joinConference(conf1->getConfId(),conf2->getConfId());
369
///Executed when the daemon signal a modification in an existing conference. Update the call list and update the TreeView
370
CALLMODEL_TEMPLATE bool CALLMODEL_T::changeConference(const QString& confId, const QString& state)
372
qDebug() << "Conf changed";
375
if (!m_sPrivateCallList_callId[confId]) {
376
qDebug() << "The conference does not exist";
380
if (!m_sPrivateCallList_callId[confId]->index) {
381
qDebug() << "The conference item does not exist";
387
///Remove a conference from the model and the TreeView
388
CALLMODEL_TEMPLATE void CALLMODEL_T::removeConference(const QString &confId)
390
if (m_sPrivateCallList_callId[confId])
391
qDebug() << "Ending conversation containing " << m_sPrivateCallList_callId[confId]->children.size() << " participants";
392
removeConference(getCall(confId));
395
///Remove a conference using it's call object
396
CALLMODEL_TEMPLATE void CALLMODEL_T::removeConference(Call* call)
398
InternalStruct* internal = m_sPrivateCallList_call[call];
401
qDebug() << "Cannot remove conference: call not found";
406
m_lConfList[call->getConfId()] = nullptr;
410
/*****************************************************************************
414
****************************************************************************/
416
///Get a call from it's widget
417
CALLMODEL_TEMPLATE Call* CALLMODEL_T::getCall ( const CallWidget widget ) const
419
if (m_sPrivateCallList_widget[widget]) {
420
return m_sPrivateCallList_widget[widget]->call_real;
425
///Get a call list from a conference
426
CALLMODEL_TEMPLATE QList<Call*> CALLMODEL_T::getCalls ( const CallWidget widget ) const
428
QList<Call*> toReturn;
429
if (m_sPrivateCallList_widget[widget] && m_sPrivateCallList_widget[widget]->conference) {
430
foreach (InternalStruct* child, m_sPrivateCallList_widget[widget]->children) {
431
toReturn << child.call_real;
437
///Get a list of every call
438
CALLMODEL_TEMPLATE QList<Call*> CALLMODEL_T::getCalls ( )
440
QList<Call*> toReturn;
441
foreach (InternalStruct* child, m_sPrivateCallList_call) {
442
toReturn << child->call_real;
447
///Is the call associated with that widget a conference
448
CALLMODEL_TEMPLATE bool CALLMODEL_T::isConference ( const CallWidget widget ) const
450
if (m_sPrivateCallList_widget[widget]) {
451
return m_sPrivateCallList_widget[widget]->conference;
456
///Is that call a conference
457
CALLMODEL_TEMPLATE bool CALLMODEL_T::isConference ( const Call* call ) const
459
if (m_sPrivateCallList_call[(Call*)call]) {
460
return m_sPrivateCallList_call[(Call*)call]->conference;
465
///Do nothing, provided for API consistency
466
CALLMODEL_TEMPLATE Call* CALLMODEL_T::getCall ( const Call* call ) const
471
///Return the calls from the "call" conference
472
CALLMODEL_TEMPLATE QList<Call*> CALLMODEL_T::getCalls ( const Call* call ) const
474
QList<Call*> toReturn;
475
if (m_sPrivateCallList_call[call] && m_sPrivateCallList_call[call]->conference) {
476
foreach (InternalStruct* child, m_sPrivateCallList_call[call]->children) {
477
toReturn << child.call_real;
483
///Is the call associated with that Index a conference
484
CALLMODEL_TEMPLATE bool CALLMODEL_T::isConference ( const Index idx ) const
486
if (m_sPrivateCallList_index[idx]) {
487
return m_sPrivateCallList_index[idx]->conference;
492
///Get the call associated with this index
493
CALLMODEL_TEMPLATE Call* CALLMODEL_T::getCall ( const Index idx ) const
495
if (m_sPrivateCallList_index[idx]) {
496
return m_sPrivateCallList_index[idx]->call_real;
498
qDebug() << "Call not found";
502
///Get the call associated with that conference index
503
CALLMODEL_TEMPLATE QList<Call*> CALLMODEL_T::getCalls ( const Index idx ) const
505
QList<Call*> toReturn;
506
if (m_sPrivateCallList_index[idx] && m_sPrivateCallList_index[idx]->conference) {
507
foreach (InternalStruct* child, m_sPrivateCallList_index[idx]->children) {
508
toReturn << child.call_real;
514
///Is the call associated with that ID a conference
515
CALLMODEL_TEMPLATE bool CALLMODEL_T::isConference ( const QString& callId ) const
517
if (m_sPrivateCallList_callId[callId]) {
518
return m_sPrivateCallList_callId[callId]->conference;
523
///Get the call associated with this ID
524
CALLMODEL_TEMPLATE Call* CALLMODEL_T::getCall ( const QString& callId ) const
526
if (m_sPrivateCallList_callId[callId]) {
527
return m_sPrivateCallList_callId[callId]->call_real;
532
///Get the calls associated with this ID
533
CALLMODEL_TEMPLATE QList<Call*> CALLMODEL_T::getCalls ( const QString& callId ) const
535
QList<Call*> toReturn;
536
if (m_sPrivateCallList_callId[callId] && m_sPrivateCallList_callId[callId]->conference) {
537
foreach (InternalStruct* child, m_sPrivateCallList_callId[callId]->children) {
538
toReturn << child.callId_real;
544
///Get the index associated with this call
545
CALLMODEL_TEMPLATE Index CALLMODEL_T::getIndex ( const Call* call ) const
547
if (m_sPrivateCallList_call[(Call*)call]) {
548
return m_sPrivateCallList_call[(Call*)call]->index;
553
///Get the index associated with this index (dummy implementation)
554
CALLMODEL_TEMPLATE Index CALLMODEL_T::getIndex ( const Index idx ) const
556
if (m_sPrivateCallList_index[idx]) {
557
return m_sPrivateCallList_index[idx]->index;
562
///Get the index associated with this call
563
CALLMODEL_TEMPLATE Index CALLMODEL_T::getIndex ( const CallWidget widget ) const
565
if (m_sPrivateCallList_widget[widget]) {
566
return m_sPrivateCallList_widget[widget]->index;
571
///Get the index associated with this ID
572
CALLMODEL_TEMPLATE Index CALLMODEL_T::getIndex ( const QString& callId ) const
574
if (m_sPrivateCallList_callId[callId]) {
575
return m_sPrivateCallList_callId[callId]->index;
580
///Get the widget associated with this call
581
CALLMODEL_TEMPLATE CallWidget CALLMODEL_T::getWidget ( const Call* call ) const
583
if (m_sPrivateCallList_call[call]) {
584
return m_sPrivateCallList_call[call]->call;
589
///Get the widget associated with this ID
590
CALLMODEL_TEMPLATE CallWidget CALLMODEL_T::getWidget ( const Index idx ) const
592
if (m_sPrivateCallList_index[idx]) {
593
return m_sPrivateCallList_index[idx]->call;
598
///Get the widget associated with this widget (dummy)
599
CALLMODEL_TEMPLATE CallWidget CALLMODEL_T::getWidget ( const CallWidget widget ) const
601
if (m_sPrivateCallList_widget[widget]) {
602
return m_sPrivateCallList_widget[widget]->call;
607
///Get the widget associated with this ID
608
CALLMODEL_TEMPLATE CallWidget CALLMODEL_T::getWidget ( const QString& widget ) const
610
if (m_sPrivateCallList_widget[widget]) {
611
return m_sPrivateCallList_widget[widget]->call;
616
///Common set of instruction shared by all gui updater
617
CALLMODEL_TEMPLATE bool CALLMODEL_T::updateCommon(Call* call)
619
if (!m_sPrivateCallList_call[call] && dynamic_cast<Call*>(call)) {
620
m_sPrivateCallList_call [ call ] = new InternalStruct ;
621
m_sPrivateCallList_call [ call ]->call_real = call ;
622
m_sPrivateCallList_call [ call ]->conference = false ;
623
m_sPrivateCallList_callId [ call->getCallId() ] = m_sPrivateCallList_call[call] ;
630
///Update the widget associated with this call
631
CALLMODEL_TEMPLATE bool CALLMODEL_T::updateWidget (Call* call, CallWidget value )
633
if (!updateCommon(call)) return false;
634
m_sPrivateCallList_call[call]->call = value ;
635
m_sPrivateCallList_widget[value] = m_sPrivateCallList_call[call] ;
639
///Update the index associated with this call
640
CALLMODEL_TEMPLATE bool CALLMODEL_T::updateIndex (Call* call, Index value )
643
if (!m_sPrivateCallList_call[call])
645
m_sPrivateCallList_call[call]->index = value ;
646
m_sPrivateCallList_index[value] = m_sPrivateCallList_call[call] ;