1
/***************************************************************************
2
* Copyright (C) 2009-2013 by Savoir-Faire Linux *
3
* Author : Emmanuel Lepage Valle <emmanuel.lepage@savoirfairelinux.com >*
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 3 of the License, or *
8
* (at your option) any later version. *
10
* This program 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 *
13
* GNU 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
**************************************************************************/
23
#include <QtGui/QTreeWidget>
24
#include <QtGui/QTreeWidgetItem>
25
#include <QtGui/QPushButton>
26
#include <QtGui/QSpacerItem>
27
#include <QtGui/QGridLayout>
28
#include <QtGui/QLabel>
29
#include <QtGui/QDockWidget>
34
#include <KStandardDirs>
37
#include "lib/contact.h"
38
#include "lib/sflphone_const.h"
39
#include "lib/callmanager_interface_singleton.h"
40
#include "klib/akonadibackend.h"
41
#include "klib/configurationskeleton.h"
42
#include "klib/helperfunctions.h"
45
#include "sflphoneview.h"
46
#include "widgets/calltreeitem.h"
48
#include "sflphoneaccessibility.h"
49
#include "widgets/callviewoverlaytoolbar.h"
50
#include "widgets/tips/dialpadtip.h"
51
#include "widgets/tips/tipcollection.h"
52
#include "widgets/calltreeitemdelegate.h"
53
#include "widgets/callviewoverlay.h"
54
#include "klib/tipmanager.h"
56
///Retrieve current and older calls from the daemon, fill history and the calls TreeView and enable drag n' drop
57
CallView::CallView(QWidget* parent) : QTreeWidget(parent),m_pActiveOverlay(0),m_pCallPendingTransfer(0),m_pCanvasToolbar(0)
60
setAcceptDrops (true );
61
setDragEnabled (true );
63
setUniformRowHeights(false);
64
setRootIsDecorated (false);
67
CallTreeItemDelegate *delegate = new CallTreeItemDelegate(this,palette());
68
setItemDelegate(delegate);
69
setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
71
QString image = "<img width=100 height=100 src='"+KStandardDirs::locate("data","sflphone-client-kde/transferarraw.png")+"' />";
73
m_pTransferOverlay = new CallViewOverlay ( this );
74
m_pTransferLE = new KLineEdit ( m_pTransferOverlay );
75
QGridLayout* gl = new QGridLayout ( m_pTransferOverlay );
76
QLabel* lblImg = new QLabel ( image );
77
m_pCanvasToolbar = new CallViewOverlayToolbar(this);
78
TipCollection::setManager(new TipManager(this));
80
m_pTransferLE->setPlaceholderText(i18n("Enter transfer number"));
81
m_pTransferLE->setAlignment(Qt::AlignCenter);
82
m_pTransferLE->setStyleSheet("border-radius:4px;border:1px solid #bbbbbb;height:35px;font-size:large;text-align:center;background-color:transparent;\
83
color:#bbbbbb;margin-left:10px;margin-right:10px;");
85
m_pTransferOverlay->setVisible(false);
86
m_pTransferOverlay->resize(size());
87
m_pTransferOverlay->setCornerWidget(lblImg);
88
m_pTransferOverlay->setAccessMessage(i18n("Please enter a transfer number and press Enter, press Escape to cancel"));
90
gl->addItem (new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Minimum), 0 , 0 , 1 , 3 );
91
gl->addWidget(m_pTransferLE , 1 , 0 , 1 , 3 );
92
gl->addItem (new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Minimum), 2 , 0 , 1 , 3 );
94
foreach(Call* active, SFLPhone::model()->getCallList()) {
98
foreach(Call* active, SFLPhone::model()->getConferenceList()) {
99
if (qobject_cast<Call*>(active)) //As of May 2012, the daemon still produce fake conferences
100
addConference(active);
104
//User Interface even
105
// SENDER SIGNAL RECEIVER SLOT /
106
/**/connect(this , SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)) , this, SLOT(itemDoubleClicked(QTreeWidgetItem*,int)) );
107
/**/connect(this , SIGNAL(itemClicked(QTreeWidgetItem*,int)) , this, SLOT(itemClicked(QTreeWidgetItem*,int)) );
108
/**/connect(this , SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)) , this, SLOT(itemClicked(QTreeWidgetItem*)) );
109
/**/connect(SFLPhone::model() , SIGNAL(conferenceCreated(Call*)) , this, SLOT(addConference(Call*)) );
110
/**/connect(SFLPhone::model() , SIGNAL(conferenceChanged(Call*)) , this, SLOT(conferenceChanged(Call*)) );
111
/**/connect(SFLPhone::model() , SIGNAL(aboutToRemoveConference(Call*)) , this, SLOT(conferenceRemoved(Call*)) );
112
/**/connect(SFLPhone::model() , SIGNAL(callAdded(Call*,Call*)) , this, SLOT(addCall(Call*,Call*)) );
113
/**/connect(m_pTransferLE , SIGNAL(returnPressed()) , this, SLOT(transfer()) );
114
/**/connect(m_pCanvasToolbar , SIGNAL(visibilityChanged(bool)) , this, SLOT(moveCanvasTip()) );
117
//TODO remove this section
118
//BEGIN On canvas toolbar
119
QPalette p = viewport()->palette();
120
p.setBrush(QPalette::Base, QBrush(TipCollection::manager()->getImage()));
121
viewport()->setPalette(p);
123
setAutoFillBackground(true);
124
if (!SFLPhone::model()->getCallList().size())
125
TipCollection::manager()->setCurrentTip(TipCollection::dialPad());
126
//END on canvas toolbar
131
CallView::~CallView()
133
delete m_pTransferLE;
134
if (m_pTransferOverlay) delete m_pTransferOverlay;
137
///A tree is not a good representation, remove branch and skin everything
138
void CallView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const
147
/*****************************************************************************
149
* Drag and drop related code *
151
****************************************************************************/
153
///Called when someone try to drop something on the tree
154
void CallView::dragEnterEvent ( QDragEnterEvent *e )
156
kDebug() << "Potential drag event enter";
160
///When a drag position change
161
void CallView::dragMoveEvent ( QDragMoveEvent *e )
166
///When a drag event is leaving the widget
167
void CallView::dragLeaveEvent ( QDragLeaveEvent *e )
169
kDebug() << "Potential drag event leave";
173
///Proxy to handle transfer mime data
174
void CallView::transferDropEvent(Call* call,QMimeData* data)
176
QByteArray encodedCallId = data->data( MIME_CALLID );
177
SFLPhone::model()->attendedTransfer(SFLPhone::model()->getCall(encodedCallId),call);
180
///Proxy to handle conversation mime data
181
void CallView::conversationDropEvent(Call* call,QMimeData* data)
183
kDebug() << "Calling real drag and drop function";
184
dropMimeData(SFLPhone::model()->getIndex(call), 0, data, (Qt::DropAction)0);
187
///A call is dropped on another call
188
bool CallView::callToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
192
QByteArray encodedCallId = data->data( MIME_CALLID );
193
if (!QString(encodedCallId).isEmpty()) {
194
// if (SFLPhone::model()->getIndex(encodedCallId) && dynamic_cast<Call*>(SFLPhone::model()->getCall(encodedCallId))) //Prevent a race
195
// clearArtefact(SFLPhone::model()->getIndex(encodedCallId));
198
kDebug() << "Call dropped on empty space";
199
if (SFLPhone::model()->getIndex(encodedCallId)->parent()) {
200
kDebug() << "Detaching participant";
201
SFLPhone::model()->detachParticipant(SFLPhone::model()->getCall(encodedCallId));
204
kDebug() << "The call is not in a conversation (doing nothing)";
208
if (SFLPhone::model()->getCall(parent)->getCallId() == QString(encodedCallId)) {
209
kDebug() << "Call dropped on itself (doing nothing)";
212
else if (SFLPhone::model()->getIndex(encodedCallId) == parent) {
213
kDebug() << "Dropping conference on itself (doing nothing)";
217
if ((parent->childCount()) && (SFLPhone::model()->getIndex(encodedCallId)->childCount())) {
218
kDebug() << "Merging two conferences";
219
SFLPhone::model()->mergeConferences(SFLPhone::model()->getCall(parent),SFLPhone::model()->getCall(encodedCallId));
222
else if ((parent->parent()) || (parent->childCount())) {
223
kDebug() << "Call dropped on a conference";
225
if (SFLPhone::model()->getIndex(encodedCallId)->childCount() && (SFLPhone::model()->getIndex(encodedCallId)->childCount()) && (!parent->childCount())) {
226
kDebug() << "Conference dropped on a call (doing nothing)";
230
QTreeWidgetItem* call1 = SFLPhone::model()->getIndex(encodedCallId);
231
QTreeWidgetItem* call2 = (parent->parent())?parent->parent():parent;
233
if (call1->parent()) {
234
kDebug() << "Call 1 is part of a conference";
235
if (call1->parent() == call2) {
236
kDebug() << "Call dropped on it's own conference (doing nothing)";
239
else if (SFLPhone::model()->getIndex(call1)->childCount()) {
240
kDebug() << "Merging two conferences";
241
SFLPhone::model()->mergeConferences(SFLPhone::model()->getCall(call1),SFLPhone::model()->getCall(call2));
243
else if (call1->parent()) {
244
kDebug() << "Moving call from a conference to an other";
245
SFLPhone::model()->detachParticipant(SFLPhone::model()->getCall(encodedCallId));
248
kDebug() << "Adding participant";
249
int state = SFLPhone::model()->getCall(call1)->getState();
250
if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFERRED || state == CALL_STATE_TRANSF_HOLD) {
251
SFLPhone::model()->getCall(call1)->actionPerformed(CALL_ACTION_ACCEPT);
253
state = SFLPhone::model()->getCall(call2)->getState();
254
if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFERRED || state == CALL_STATE_TRANSF_HOLD) {
255
SFLPhone::model()->getCall(call2)->actionPerformed(CALL_ACTION_ACCEPT);
257
SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call1),SFLPhone::model()->getCall(call2));
260
else if (SFLPhone::model()->getIndex(encodedCallId) && (SFLPhone::model()->getIndex(encodedCallId)->childCount()) && (!parent->childCount())) {
261
kDebug() << "Call dropped on it's own conference (doing nothing)";
265
kDebug() << "Call dropped on another call";
266
SFLPhone::model()->createConferenceFromCall(SFLPhone::model()->getCall(encodedCallId),SFLPhone::model()->getCall(parent));
272
///A string containing a call number is dropped on a call
273
bool CallView::phoneNumberToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
277
QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
278
if (!QString(encodedPhoneNumber).isEmpty()) {
279
Contact* contact = AkonadiBackend::getInstance()->getContactByPhone(encodedPhoneNumber,true);
281
name = (contact)?contact->getFormattedName():i18nc("Unknown peer","Unknown");
282
Call* call2 = SFLPhone::model()->addDialingCall(name, AccountList::getCurrentAccount());
284
call2->appendText(QString(encodedPhoneNumber));
286
//Dropped on free space
287
kDebug() << "Adding new dialing call";
289
else if (parent->childCount() || parent->parent()) {
290
//Dropped on a conversation
291
QTreeWidgetItem* call = (parent->parent())?parent->parent():parent;
292
SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call),call2);
296
call2->actionPerformed(CALL_ACTION_ACCEPT);
297
int state = SFLPhone::model()->getCall(parent)->getState();
298
if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFERRED || state == CALL_STATE_TRANSF_HOLD) {
299
SFLPhone::model()->getCall(parent)->actionPerformed(CALL_ACTION_ACCEPT);
301
SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
305
HelperFunctions::displayNoAccountMessageBox(this);
309
} //phoneNumberToCall
311
///A contact ID is dropped on a call
312
bool CallView::contactToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
314
kDebug() << "contactToCall";
317
QByteArray encodedContact = data->data( MIME_CONTACT );
318
if (!QString(encodedContact).isEmpty()) {
319
Contact* contact = AkonadiBackend::getInstance()->getContactByUid(encodedContact);
321
Call* call2 = nullptr;
322
if (!SFLPhone::app()->view()->selectCallPhoneNumber(&call2,contact))
325
//Dropped on free space
326
kDebug() << "Adding new dialing call";
328
else if (parent->childCount() || parent->parent()) {
329
//Dropped on a conversation
330
QTreeWidgetItem* call = (parent->parent())?parent->parent():parent;
331
SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call),call2);
334
call2->actionPerformed(CALL_ACTION_ACCEPT);
335
int state = SFLPhone::model()->getCall(parent)->getState();
336
if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFERRED || state == CALL_STATE_TRANSF_HOLD) {
337
SFLPhone::model()->getCall(parent)->actionPerformed(CALL_ACTION_ACCEPT);
339
SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
346
///Action performed when an item is dropped on the TreeView
347
bool CallView::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
352
QByteArray encodedCallId = data->data( MIME_CALLID );
353
QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
354
QByteArray encodedContact = data->data( MIME_CONTACT );
356
if (!QString(encodedCallId).isEmpty()) {
357
kDebug() << "CallId dropped"<< QString(encodedCallId);
358
callToCall(parent, index, data, action);
360
else if (!QString(encodedPhoneNumber).isEmpty()) {
361
kDebug() << "PhoneNumber dropped"<< QString(encodedPhoneNumber);
362
phoneNumberToCall(parent, index, data, action);
364
else if (!QString(encodedContact).isEmpty()) {
365
kDebug() << "Contact dropped"<< QString(encodedContact);
366
contactToCall(parent, index, data, action);
372
///Encode data to be tranported during the drag n' drop operation
373
QMimeData* CallView::mimeData( const QList<QTreeWidgetItem *> items) const
375
kDebug() << "A call is being dragged";
376
if (items.size() < 1) {
380
QMimeData *mimeData = new QMimeData();
382
//Call ID for internal call merging and spliting
383
if (SFLPhone::model()->getCall(items[0])->isConference()) {
384
mimeData->setData(MIME_CALLID, SFLPhone::model()->getCall(items[0])->getConfId().toAscii());
387
mimeData->setData(MIME_CALLID, SFLPhone::model()->getCall(items[0])->getCallId().toAscii());
390
//Plain text for other applications
391
mimeData->setData(MIME_PLAIN_TEXT, QString(SFLPhone::model()->getCall(items[0])->getPeerName()+'\n'+SFLPhone::model()->getCall(items[0])->getPeerPhoneNumber()).toAscii());
393
CallTreeItem* widget = dynamic_cast<CallTreeItem*>(itemWidget(items[0],0));
395
widget->setDragged(true);
402
/*****************************************************************************
404
* Call related code *
406
****************************************************************************/
408
///Add a call in the model structure, the call must exist before being added to the model
409
Call* CallView::addCall(Call* call, Call* parent)
411
QTreeWidgetItem* callItem = new QTreeWidgetItem();
412
SFLPhone::model()->updateIndex(call,callItem);
413
insertItem(callItem,parent);
415
setCurrentItem(callItem);
417
connect(call, SIGNAL(isOver(Call*)), this, SLOT(destroyCall(Call*)));
419
//Hack to raise call dock if it is bellow current dock
420
QWidget* parW = qobject_cast<QWidget*>(QWidget::parent());
422
QWidget* parW2 = qobject_cast<QWidget*>(parW->parent());
424
QDockWidget* dock = qobject_cast<QDockWidget*>(parW2->parent());
432
if (TipCollection::manager()->currentTip()==TipCollection::dialPad())
433
TipCollection::manager()->setCurrentTip(nullptr);
439
void CallView::transfer()
441
if (m_pCallPendingTransfer && !m_pTransferLE->text().isEmpty()) {
442
SFLPhone::model()->transfer(m_pCallPendingTransfer,m_pTransferLE->text());
443
if (ConfigurationSkeleton::enableVoiceFeedback()) {
444
SFLPhoneAccessibility::getInstance()->say(i18n("Your call have been transferred to %1", m_pTransferLE->text()));
448
m_pCallPendingTransfer = 0;
449
m_pTransferLE->clear();
451
m_pTransferOverlay->setVisible(false);
454
/*****************************************************************************
456
* View related code *
458
****************************************************************************/
460
///Show the transfer overlay
461
void CallView::showTransferOverlay(Call* call)
463
if (!m_pTransferOverlay) {
464
kDebug() << "Creating overlay";
466
m_pTransferOverlay->setVisible(true);
467
m_pCallPendingTransfer = call;
468
m_pActiveOverlay = m_pTransferOverlay;
469
m_pTransferLE->setFocus();
470
connect(call,SIGNAL(isOver(Call*)),this,SLOT(hideOverlay()));
473
///Is there an active overlay
474
bool CallView::haveOverlay()
476
return (m_pActiveOverlay && m_pActiveOverlay->isVisible());
479
///Remove the active overlay
480
void CallView::hideOverlay()
482
if (m_pActiveOverlay){
483
if (m_pCallPendingTransfer->getState() != CALL_STATE_OVER) {
484
m_pCallPendingTransfer->changeCurrentState( CALL_STATE_CURRENT );
485
SFLPhone::app()->view()->updateWindowCallState(); //TODO hack
487
disconnect(m_pCallPendingTransfer,SIGNAL(changed()),this,SLOT(hideOverlay()));
488
m_pActiveOverlay->setVisible(false);
491
m_pActiveOverlay = 0;
493
m_pCallPendingTransfer = 0;
496
///Be sure the size of the overlay stay the same
497
void CallView::resizeEvent (QResizeEvent *e)
499
if (m_pTransferOverlay)
500
m_pTransferOverlay->resize(size());
501
QTreeWidget::resizeEvent(e);
503
if (m_pCanvasToolbar) {
504
m_pCanvasToolbar->resize(width(),72);
505
m_pCanvasToolbar->move(0,height()-72);
509
///Set the TreeView header text
510
void CallView::setTitle(const QString& title)
512
headerItem()->setText(0,title);
515
///Return the current item
516
Call* CallView::getCurrentItem()
518
if (currentItem() && SFLPhone::model()->getCall(QTreeWidget::currentItem()))
519
return SFLPhone::model()->getCall(QTreeWidget::currentItem());
524
///Remove a TreeView item and delete it
525
bool CallView::removeItem(Call* item)
527
if (indexOfTopLevelItem(SFLPhone::model()->getIndex(item)) != -1) {
528
QTreeWidgetItem* parent = itemAt(indexOfTopLevelItem(SFLPhone::model()->getIndex(item)),0);
529
removeItemWidget(SFLPhone::model()->getIndex(item),0);
530
if (parent->childCount() == 0) //TODO this have to be done in the daemon, not here, but oops still happen too often to ignore
531
removeItemWidget(parent,0);
539
///Return the TreeView, this
540
QWidget* CallView::getWidget()
545
///Convenience wrapper around extractItem(QTreeWidgetItem*)
546
QTreeWidgetItem* CallView::extractItem(const QString& callId)
548
QTreeWidgetItem* currentItem = SFLPhone::model()->getIndex(callId);
549
return extractItem(currentItem);
552
///Extract an item from the TreeView and return it, the item is -not- deleted
553
QTreeWidgetItem* CallView::extractItem(QTreeWidgetItem* item)
557
QTreeWidgetItem* parentItem = item->parent();
560
if ((indexOfTopLevelItem(parentItem) == -1 ) || (parentItem->indexOfChild(item) == -1)) {
561
kDebug() << "The conversation does not exist";
565
QTreeWidgetItem* toReturn = parentItem->takeChild(parentItem->indexOfChild(item));
570
return takeTopLevelItem(indexOfTopLevelItem(item));
573
///Convenience wrapper around insertItem(QTreeWidgetItem*, QTreeWidgetItem*)
574
CallTreeItem* CallView::insertItem(QTreeWidgetItem* item, Call* parent)
576
return insertItem(item,(parent)?SFLPhone::model()->getIndex(parent):0);
579
///Insert a TreeView item in the TreeView as child of parent or as a top level item, also restore the item Widget
580
CallTreeItem* CallView::insertItem(QTreeWidgetItem* item, QTreeWidgetItem* parent)
582
if (!dynamic_cast<QTreeWidgetItem*>(item) && SFLPhone::model()->getCall(item) && !dynamic_cast<QTreeWidgetItem*>(parent))
586
kDebug() << "This is not a valid call";
591
insertTopLevelItem(0,item);
593
parent->addChild(item);
595
CallTreeItem* callItem = new CallTreeItem();
596
connect(callItem, SIGNAL(askTransfer(Call*)) , this, SLOT(showTransferOverlay(Call*)) );
597
connect(callItem, SIGNAL(transferDropEvent(Call*,QMimeData*)) , this, SLOT(transferDropEvent(Call*,QMimeData*)) );
598
connect(callItem, SIGNAL(conversationDropEvent(Call*,QMimeData*)), this, SLOT(conversationDropEvent(Call*,QMimeData*)));
600
SFLPhone::model()->updateWidget(SFLPhone::model()->getCall(item), callItem);
601
callItem->setCall(SFLPhone::model()->getCall(item));
603
setItemWidget(item,0,callItem);
609
///Remove a call from the interface
610
void CallView::destroyCall(Call* toDestroy)
612
if (SFLPhone::model()->getIndex(toDestroy) == currentItem())
613
setCurrentItem(nullptr);
615
if (!SFLPhone::model()->getIndex(toDestroy))
616
kDebug() << "Call not found";
617
else if (indexOfTopLevelItem(SFLPhone::model()->getIndex(toDestroy)) != -1)
618
takeTopLevelItem(indexOfTopLevelItem(SFLPhone::model()->getIndex(toDestroy)));
619
else if (SFLPhone::model()->getIndex(toDestroy)->parent()) {
620
QTreeWidgetItem* callIndex = SFLPhone::model()->getIndex(toDestroy);
621
QTreeWidgetItem* parent = callIndex->parent();
622
if (indexOfTopLevelItem(parent) != -1) {
623
parent->removeChild(callIndex);
624
if (dynamic_cast<QTreeWidgetItem*>(parent) && parent->childCount() == 0) /*This should never happen, but it does*/
625
takeTopLevelItem(indexOfTopLevelItem(parent));
629
kDebug() << "Call not found";
631
if (toDestroy->getState() == CALL_STATE_BUSY || toDestroy->getState() == CALL_STATE_FAILURE)
632
TipCollection::manager()->setCurrentTip(TipCollection::endBusy());
634
TipCollection::manager()->setCurrentTip(TipCollection::endCall());
637
/// @todo Remove the text partially covering the TreeView item widget when it is being dragged, a beter implementation is needed
638
void CallView::clearArtefact()
640
for (int i=0;i<topLevelItemCount();i++) {
641
QTreeWidgetItem* item = topLevelItem(i);
643
CallTreeItem* widget = dynamic_cast<CallTreeItem*>(itemWidget(item,0));
645
widget->setDragged(false);
647
for(int j=0;j< item->childCount();j++) {
648
QTreeWidgetItem* item2 = item->child(j);
649
CallTreeItem* widget2 = dynamic_cast<CallTreeItem*>(itemWidget(item2,0));
651
widget2->setDragged(false);
659
/*****************************************************************************
661
* Event related code *
663
****************************************************************************/
665
///When an item is double clicked
666
void CallView::itemDoubleClicked(QTreeWidgetItem* item, int column) {
668
kDebug() << "Item doubleclicked" << SFLPhone::model()->getCall(item)->getState();
669
switch(SFLPhone::model()->getCall(item)->getState()) {
670
case CALL_STATE_INCOMING:
671
SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_ACCEPT);
673
case CALL_STATE_HOLD:
674
SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_HOLD);
676
case CALL_STATE_DIALING:
677
SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_ACCEPT);
680
kDebug() << "Double clicked an item with no action on double click.";
682
} //itemDoubleClicked
684
///When an item is clicked
685
void CallView::itemClicked(QTreeWidgetItem* item, int column) {
687
Call* call = SFLPhone::model()->getCall(item);
688
call->setSelected(true);
690
if (ConfigurationSkeleton::enableReadDetails()) {
691
SFLPhoneAccessibility::getInstance()->currentCallDetails();
694
emit itemChanged(call);
695
kDebug() << "Item clicked";
699
/*****************************************************************************
701
* Conference related code *
703
****************************************************************************/
705
///Add a new conference, get the call list and update the interface as needed
706
Call* CallView::addConference(Call* conf)
708
kDebug() << "Conference created";
709
Call* newConf = conf;
711
QTreeWidgetItem* confItem = new QTreeWidgetItem();
712
SFLPhone::model()->updateIndex(conf,confItem);
714
insertItem(confItem,(QTreeWidgetItem*)0);
717
setCurrentItem(confItem);
719
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
720
const QStringList callList = callManager.getParticipantList(conf->getConfId());
722
foreach (const QString& callId, callList) {
723
kDebug() << "Adding " << callId << "to the conversation";
724
insertItem(extractItem(SFLPhone::model()->getIndex(callId)),confItem);
727
if (TipCollection::manager()->currentTip() == TipCollection::dragAndDrop()) {
728
TipCollection::manager()->hideTip(TipCollection::dragAndDrop());
734
///Executed when the daemon signal a modification in an existing conference. Update the call list and update the TreeView
735
bool CallView::conferenceChanged(Call* conf)
737
if (!dynamic_cast<Call*>(conf)) return false;
738
kDebug() << "Conference changed";
740
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
741
const QStringList callList = callManager.getParticipantList(conf->getConfId());
743
QList<QTreeWidgetItem*> buffer;
744
foreach (const QString& callId, callList) {
745
if (SFLPhone::model()->getCall(callId)) {
746
QTreeWidgetItem* item3 = extractItem(SFLPhone::model()->getIndex(callId));
747
insertItem(item3, SFLPhone::model()->getIndex(conf));
748
buffer << SFLPhone::model()->getIndex(callId);
751
kDebug() << "Call " << callId << " does not exist";
754
QTreeWidgetItem* item = SFLPhone::model()->getIndex(conf);
755
if (item) /*Can happen if the daemon crashed*/
756
for (int j =0; j < item->childCount();j++) {
757
if (buffer.indexOf(item->child(j)) == -1)
758
insertItem(extractItem(item->child(j)));
761
Q_ASSERT_X(SFLPhone::model()->getIndex(conf)->childCount() == 0,"changing conference","A conference can't have no participants");
764
} //conferenceChanged
766
///Remove a conference from the model and the TreeView
767
void CallView::conferenceRemoved(Call* conf)
769
kDebug() << "Attempting to remove conference";
770
QTreeWidgetItem* idx = SFLPhone::model()->getIndex(conf);
772
while (idx->childCount()) {
773
insertItem(extractItem(SFLPhone::model()->getIndex(conf)->child(0)));
775
takeTopLevelItem(indexOfTopLevelItem(SFLPhone::model()->getIndex(conf)));
776
kDebug() << "Conference removed";
779
kDebug() << "Conference not found";
781
} //conferenceRemoved
783
///Clear the list of old calls //TODO Clear them from the daemon
784
void CallView::clearHistory()
786
//SFLPhone::model()->getHistory().clear();
789
///Redirect keypresses to parent
790
void CallView::keyPressEvent(QKeyEvent* event) {
791
SFLPhone::app()->view()->keyPressEvent(event);
794
///Move selection using arrow keys
795
void CallView::moveSelectedItem( Qt::Key direction )
797
if (direction == Qt::Key_Left) {
798
setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft ,Qt::NoModifier));
800
else if (direction == Qt::Key_Right) {
801
setCurrentIndex(moveCursor(QAbstractItemView::MoveRight,Qt::NoModifier));
803
else if (direction == Qt::Key_Up) {
804
setCurrentIndex(moveCursor(QAbstractItemView::MoveUp ,Qt::NoModifier));
806
else if (direction == Qt::Key_Down) {
807
setCurrentIndex(moveCursor(QAbstractItemView::MoveDown ,Qt::NoModifier));
811
///Select the first call, if any
812
void CallView::selectFirstItem()
814
if (model()->rowCount()) {
815
QModelIndex firstItem = model()->index(0,0);
816
if (model()->rowCount(firstItem) > 0) {
817
firstItem = firstItem.child(0,0);
819
setCurrentIndex(firstItem);
823
///Proxy to modify the background tip position
824
void CallView::moveCanvasTip()
826
int topM(0),bottomM(0);
827
bottomM += m_pCanvasToolbar->isVisible()?m_pCanvasToolbar->height():0;
828
QModelIndex lastItem = model()->index(model()->rowCount()-1,0);
829
if (model()->rowCount(lastItem) > 0) {
830
lastItem = lastItem.child(model()->rowCount(lastItem)-1,0);
832
if (lastItem != QModelIndex()) {
833
QRect r = visualRect(lastItem);
834
topM += r.y() + r.height();
837
TipCollection::manager()->setTopMargin(topM);
838
TipCollection::manager()->setBottomMargin(bottomM);