CallView.cpp 27.3 KB
Newer Older
1
/***************************************************************************
2
 *   Copyright (C) 2009-2012 by Savoir-Faire Linux                         *
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *   Author : Emmanuel Lepage Valle <emmanuel.lepage@savoirfairelinux.com >*
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 **************************************************************************/

//Parent
22
#include "CallView.h"
23
24
25
26
27

//Qt
#include <QtGui/QInputDialog>
#include <QtGui/QTreeWidget>
#include <QtGui/QTreeWidgetItem>
28
29
30
#include <QtGui/QPushButton>
#include <QtGui/QSpacerItem>
#include <QtGui/QGridLayout>
31
#include <QtGui/QLabel>
32

33
34
//KDE
#include <KDebug>
35
#include <KLineEdit>
36
#include <KStandardDirs>
37
38

//SFLPhone library
39
#include "lib/Contact.h"
Emmanuel Lepage's avatar
Emmanuel Lepage committed
40
41
#include "lib/sflphone_const.h"
#include "lib/callmanager_interface_singleton.h"
42

43
44
//SFLPhone
#include "widgets/CallTreeItem.h"
45
#include "SFLPhone.h"
Emmanuel Lepage's avatar
Emmanuel Lepage committed
46
#include "SFLPhoneView.h"
47
#include "AkonadiBackend.h"
48

49
50

///Retrieve current and older calls from the daemon, fill history and the calls TreeView and enable drag n' drop
51
CallView::CallView(QWidget* parent) : QTreeWidget(parent),m_pCallPendingTransfer(0),m_pActiveOverlay(0)
52
53
54
55
{
   //Widget part
   setAcceptDrops(true);
   setDragEnabled(true);
56
   setAnimated(true);
57
58
59
   CallTreeItemDelegate *delegate = new CallTreeItemDelegate();
   setItemDelegate(delegate); 
   setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
60
61
62
63
   
   m_pTransferOverlay = new CallViewOverlay(this);
   m_pTransferOverlay->setVisible(false);
   m_pTransferOverlay->resize(size());
64
65
   QLabel* lblImg = new QLabel("<img width=100 height=100  src='"+KStandardDirs::locate("data","sflphone-client-kde/transferarraw.png")+"' />");
   m_pTransferOverlay->setCornerWidget(lblImg);
66
67
68
69
70
71
72
73
74
75

   m_pTransferB  = new QPushButton(m_pTransferOverlay);
   m_pTransferLE = new KLineEdit(m_pTransferOverlay);
   m_pTransferB->setText("Transfer");
   m_pTransferB->setMaximumSize(70,9000);
   QGridLayout* gl = new QGridLayout(m_pTransferOverlay);
   gl->addItem(new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Minimum),0,0,1,3);
   gl->addWidget(m_pTransferLE,1,1,1,2);
   gl->addWidget(m_pTransferB,1,4,1,2);
   gl->addItem(new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Minimum),2,0,1,3);
76

Emmanuel Lepage's avatar
Emmanuel Lepage committed
77
   //User Interface even
78
79
80
81
82
83
84
85
   //              SENDER                                   SIGNAL                              RECEIVER                     SLOT                        /
   /**/connect(this              , SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)              ) , this, SLOT( itemDoubleClicked(QTreeWidgetItem*,int)) );
   /**/connect(this              , SIGNAL(itemClicked(QTreeWidgetItem*,int)                    ) , this, SLOT( itemClicked(QTreeWidgetItem*,int))       );
   /**/connect(this              , SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)) , this, SLOT( itemClicked(QTreeWidgetItem*))           );
   /**/connect(SFLPhone::model() , SIGNAL(conferenceCreated(Call*)                             ) , this, SLOT( addConference(Call*))                    );
   /**/connect(SFLPhone::model() , SIGNAL(conferenceChanged(Call*)                             ) , this, SLOT( conferenceChanged(Call*))                );
   /**/connect(SFLPhone::model() , SIGNAL(aboutToRemoveConference(Call*)                       ) , this, SLOT( conferenceRemoved(Call*))                );
   /**/connect(SFLPhone::model() , SIGNAL(callAdded(Call*,Call*)                               ) , this, SLOT( addCall(Call*,Call*))                    );
86
87
   /**/connect(m_pTransferB      , SIGNAL(clicked()                                            ) , this, SLOT( transfer())                              );
   /**/connect(m_pTransferLE     , SIGNAL(returnPressed()                                      ) , this, SLOT( transfer())                              );
88
   /*                                                                                                                                                   */
89

90
91
92
93
94
95
96
97
98
}


/*****************************************************************************
 *                                                                           *
 *                        Drag and drop related code                         *
 *                                                                           *
 ****************************************************************************/

99
100
101
102
103
104
105
106
107
108
///Called when someone try to drop something on the tree
void CallView::dragEnterEvent ( QDragEnterEvent *e )
{
   kDebug() << "Potential drag event enter";
   e->accept();
}

///When a drag position change
void CallView::dragMoveEvent  ( QDragMoveEvent  *e )
{
109
   e->accept();
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
}

///When a drag event is leaving the widget
void CallView::dragLeaveEvent ( QDragLeaveEvent *e )
{
   kDebug() << "Potential drag event leave";
   e->accept();
}

///Add some child to the QTreeWidgetItem to show drop options (conference or transfer)
void CallView::showDropOptions(CallTreeItem* widget)
{
   //TODO remove?
}

///Proxy to handle transfer mime data
void CallView::transferDropEvent(Call* call,QMimeData* data)
{
   QByteArray encodedCallId = data->data( MIME_CALLID );
   SFLPhone::model()->attendedTransfer(SFLPhone::model()->getCall(encodedCallId),call);
}

///Proxy to handle conversation mime data
void CallView::conversationDropEvent(Call* call,QMimeData* data)
{
   kDebug() << "Calling real drag and drop function";
   dropMimeData(SFLPhone::model()->getIndex(call), 0, data, (Qt::DropAction)0);
}

Emmanuel Lepage's avatar
Emmanuel Lepage committed
139
///A call is dropped on another call
140
bool CallView::callToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
141
142
143
{
   Q_UNUSED(index)
   Q_UNUSED(action)
144
145
   QByteArray encodedCallId      = data->data( MIME_CALLID      );
   if (!QString(encodedCallId).isEmpty()) {
146
147
      if (SFLPhone::model()->getIndex(encodedCallId))
        clearArtefact(SFLPhone::model()->getIndex(encodedCallId));
148

149
      if (!parent) {
150
         kDebug() << "Call dropped on empty space";
151
         if (SFLPhone::model()->getIndex(encodedCallId)->parent()) {
152
            kDebug() << "Detaching participant";
153
            SFLPhone::model()->detachParticipant(SFLPhone::model()->getCall(encodedCallId));
154
155
         }
         else
156
            kDebug() << "The call is not in a conversation (doing nothing)";
157
158
         return true;
      }
159

160
      if (SFLPhone::model()->getCall(parent)->getCallId() == QString(encodedCallId)) {
161
         kDebug() << "Call dropped on itself (doing nothing)";
162
163
         return true;
      }
164

165
      if ((parent->childCount()) && (SFLPhone::model()->getIndex(encodedCallId)->childCount())) {
166
         kDebug() << "Merging two conferences";
167
         SFLPhone::model()->mergeConferences(SFLPhone::model()->getCall(parent),SFLPhone::model()->getCall(encodedCallId));
168
169
170
         return true;
      }
      else if ((parent->parent()) || (parent->childCount())) {
171
         kDebug() << "Call dropped on a conference";
172

173
         if ((SFLPhone::model()->getIndex(encodedCallId)->childCount()) && (!parent->childCount())) {
174
            kDebug() << "Conference dropped on a call (doing nothing)";
175
176
            return true;
         }
177

178
         QTreeWidgetItem* call1 = SFLPhone::model()->getIndex(encodedCallId);
179
         QTreeWidgetItem* call2 = (parent->parent())?parent->parent():parent;
180

181
         if (call1->parent()) {
182
            kDebug() << "Call 1 is part of a conference";
183
            if (call1->parent() == call2) {
184
               kDebug() << "Call dropped on it's own conference (doing nothing)";
185
186
               return true;
            }
187
            else if (SFLPhone::model()->getIndex(call1)->childCount()) {
188
               kDebug() << "Merging two conferences";
189
               SFLPhone::model()->mergeConferences(SFLPhone::model()->getCall(call1),SFLPhone::model()->getCall(call2));
190
191
            }
            else if (call1->parent()) {
192
               kDebug() << "Moving call from a conference to an other";
193
               SFLPhone::model()->detachParticipant(SFLPhone::model()->getCall(encodedCallId));
194
195
            }
         }
196
         kDebug() << "Adding participant";
197
         int state = SFLPhone::model()->getCall(call1)->getState();
198
         if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFER || state == CALL_STATE_TRANSF_HOLD) {
199
            SFLPhone::model()->getCall(call1)->actionPerformed(CALL_ACTION_ACCEPT);
200
         }
201
         state = SFLPhone::model()->getCall(call2)->getState();
202
         if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFER || state == CALL_STATE_TRANSF_HOLD) {
203
            SFLPhone::model()->getCall(call2)->actionPerformed(CALL_ACTION_ACCEPT);
204
         }
205
         SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call1),SFLPhone::model()->getCall(call2));
206
207
         return true;
      }
208
      else if ((SFLPhone::model()->getIndex(encodedCallId)->childCount()) && (!parent->childCount())) {
209
         kDebug() << "Call dropped on it's own conference (doing nothing)";
210
211
212
         return true;
      }

213
      kDebug() << "Call dropped on another call";
214
      SFLPhone::model()->createConferenceFromCall(SFLPhone::model()->getCall(encodedCallId),SFLPhone::model()->getCall(parent));
215
216
      return true;
   }
217
218
219
   return false;
}

Emmanuel Lepage's avatar
Emmanuel Lepage committed
220
///A string containing a call number is dropped on a call
221
222
223
224
225
226
227
228
229
230
231
232
bool CallView::phoneNumberToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
{
   Q_UNUSED(index)
   Q_UNUSED(action)
   QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
   if (!QString(encodedPhoneNumber).isEmpty()) {
      Contact* contact = AkonadiBackend::getInstance()->getContactByPhone(encodedPhoneNumber);
      QString name;
      if (contact)
         name = contact->getFormattedName();
      else
         name = "Unknow";
233
      Call* call2 = SFLPhone::model()->addDialingCall(name, SFLPhone::model()->getCurrentAccountId());
234
235
236
      call2->appendText(QString(encodedPhoneNumber));
      if (!parent) {
         //Dropped on free space
237
         kDebug() << "Adding new dialing call";
238
239
240
241
      }
      else if (parent->childCount() || parent->parent()) {
         //Dropped on a conversation
         QTreeWidgetItem* call = (parent->parent())?parent->parent():parent;
242
         SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call),call2);
243
244
245
246
      }
      else {
         //Dropped on call
         call2->actionPerformed(CALL_ACTION_ACCEPT);
247
         int state = SFLPhone::model()->getCall(parent)->getState();
248
         if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFER || state == CALL_STATE_TRANSF_HOLD) {
249
            SFLPhone::model()->getCall(parent)->actionPerformed(CALL_ACTION_ACCEPT);
250
         }
251
         SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
252
253
254
255
256
      }
   }
   return false;
}

Emmanuel Lepage's avatar
Emmanuel Lepage committed
257
///A contact ID is dropped on a call
258
259
bool CallView::contactToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
{
260
   kDebug() << "contactToCall";
261
262
   Q_UNUSED( index  )
   Q_UNUSED( action )
263
264
265
266
267
268
   QByteArray encodedContact = data->data( MIME_CONTACT );
   if (!QString(encodedContact).isEmpty()) {
      Contact* contact = AkonadiBackend::getInstance()->getContactByUid(encodedContact);
      if (contact) {
         Call* call2;
         if (contact->getPhoneNumbers().count() == 1) {
269
            call2 = SFLPhone::model()->addDialingCall(contact->getFormattedName(), SFLPhone::model()->getCurrentAccountId());
270
271
272
273
274
275
276
277
278
279
280
281
            call2->appendText(contact->getPhoneNumbers()[0]->getNumber());
         }
         else if (contact->getPhoneNumbers().count() > 1) {
            bool ok = false;
            QHash<QString,QString> map;
            QStringList list;
            foreach (Contact::PhoneNumber* number, contact->getPhoneNumbers()) {
               map[number->getType()+" ("+number->getNumber()+")"] = number->getNumber();
               list << number->getType()+" ("+number->getNumber()+")";
            }
            QString result = QInputDialog::getItem (this, QString("Select phone number"), QString("This contact have many phone number, please select the one you wish to call"), list, 0, false, &ok);
            if (ok) {
282
               call2 = SFLPhone::model()->addDialingCall(contact->getFormattedName(), SFLPhone::model()->getCurrentAccountId());
283
284
285
               call2->appendText(map[result]);
            }
            else {
286
               kDebug() << "Operation cancelled";
287
288
289
290
               return false;
            }
         }
         else {
291
            kDebug() << "This contact have no valid phone number";
292
293
294
295
            return false;
         }
         if (!parent) {
            //Dropped on free space
296
            kDebug() << "Adding new dialing call";
297
298
299
300
         }
         else if (parent->childCount() || parent->parent()) {
            //Dropped on a conversation
            QTreeWidgetItem* call = (parent->parent())?parent->parent():parent;
301
            SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call),call2);
302
303
304
305
         }
         else {
            //Dropped on call
            call2->actionPerformed(CALL_ACTION_ACCEPT);
306
            int state = SFLPhone::model()->getCall(parent)->getState();
307
            if(state == CALL_STATE_INCOMING || state == CALL_STATE_DIALING || state == CALL_STATE_TRANSFER || state == CALL_STATE_TRANSF_HOLD) {
308
               SFLPhone::model()->getCall(parent)->actionPerformed(CALL_ACTION_ACCEPT);
309
            }
310
            SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
311
312
313
314
315
316
317
318
319
320
321
         }
      }
   }
   return false;
}

///Action performed when an item is dropped on the TreeView
bool CallView::dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) 
{
   Q_UNUSED(index)
   Q_UNUSED(action)
322
   
323
324
325
326
327
   QByteArray encodedCallId      = data->data( MIME_CALLID      );
   QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
   QByteArray encodedContact     = data->data( MIME_CONTACT     );

   if (!QString(encodedCallId).isEmpty()) {
328
      kDebug() << "CallId dropped"<< QString(encodedCallId);
329
330
331
      callToCall(parent, index, data, action);
   }
   else if (!QString(encodedPhoneNumber).isEmpty()) {
332
      kDebug() << "PhoneNumber dropped"<< QString(encodedPhoneNumber);
333
334
335
      phoneNumberToCall(parent, index, data, action);
   }
   else if (!QString(encodedContact).isEmpty()) {
336
      kDebug() << "Contact dropped"<< QString(encodedContact);
337
338
      contactToCall(parent, index, data, action);
   }
339
340
341
342
343
344
   return false;
}

///Encode data to be tranported during the drag n' drop operation
QMimeData* CallView::mimeData( const QList<QTreeWidgetItem *> items) const
{   
345
   kDebug() << "A call is being dragged";
346
347
348
349
350
351
352
   if (items.size() < 1) {
      return NULL;
   }
   
   QMimeData *mimeData = new QMimeData();
   
   //Call ID for internal call merging and spliting
353
354
   if (SFLPhone::model()->getCall(items[0])->isConference()) {
      mimeData->setData(MIME_CALLID, SFLPhone::model()->getCall(items[0])->getConfId().toAscii());
355
356
   }
   else {
357
      mimeData->setData(MIME_CALLID, SFLPhone::model()->getCall(items[0])->getCallId().toAscii());
358
359
360
   }
   
   //Plain text for other applications
361
   mimeData->setData(MIME_PLAIN_TEXT, QString(SFLPhone::model()->getCall(items[0])->getPeerName()+"\n"+SFLPhone::model()->getCall(items[0])->getPeerPhoneNumber()).toAscii());
362
363
   
   //TODO Comment this line if you don't want to see ugly artefact, but the caller details will not be visible while dragged
364
   items[0]->setText(0, SFLPhone::model()->getCall(items[0])->getPeerName() + "\n" + SFLPhone::model()->getCall(items[0])->getPeerPhoneNumber());
365
366
367
368
369
370
371
372
373
374
375
376
377
378
   return mimeData;
}


/*****************************************************************************
 *                                                                           *
 *                            Call related code                              *
 *                                                                           *
 ****************************************************************************/

///Add a call in the model structure, the call must exist before being added to the model
Call* CallView::addCall(Call* call, Call* parent) 
{
   QTreeWidgetItem* callItem = new QTreeWidgetItem();
379
   SFLPhone::model()->updateIndex(call,callItem);
380
381
382
383
384
385
386
387
   insertItem(callItem,parent);
   
   setCurrentItem(callItem);
   
   connect(call, SIGNAL(isOver(Call*)), this, SLOT(destroyCall(Call*)));
   return call;
}

388
389
390
391
392
393
394
395
396
397
398
///Transfer a call
void CallView::transfer()
{
   if (m_pCallPendingTransfer) {
      SFLPhone::model()->transfer(m_pCallPendingTransfer,m_pTransferLE->text());
      m_pCallPendingTransfer = 0;
      m_pTransferLE->clear();
      m_pTransferOverlay->setVisible(false);
   }
}

399
400
401
402
403
404
/*****************************************************************************
 *                                                                           *
 *                            View related code                              *
 *                                                                           *
 ****************************************************************************/

405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
///Show the transfer overlay
void CallView::showTransferOverlay(Call* call)
{
   if (!m_pTransferOverlay) {
      kDebug() << "Creating overlay";
   }
   m_pTransferOverlay->setVisible(true);
   m_pCallPendingTransfer = call;
   m_pActiveOverlay = m_pTransferOverlay;
   m_pTransferLE->setFocus();
   connect(call,SIGNAL(changed()),this,SLOT(hideOverlay()));
}

///Is there an active overlay
bool CallView::haveOverlay()
{
   return (m_pActiveOverlay && m_pActiveOverlay->isVisible());
}

///Remove the active overlay
void CallView::hideOverlay()
{
   if (m_pActiveOverlay)
      m_pActiveOverlay->setVisible(false);
   m_pActiveOverlay = 0;
}

///Be sure the size of the overlay stay the same
void CallView::resizeEvent (QResizeEvent *e)
{
   if (m_pTransferOverlay)
      m_pTransferOverlay->resize(size());
   QTreeWidget::resizeEvent(e);
}

440
///Set the TreeView header text
441
void CallView::setTitle(const QString& title) 
442
443
444
445
446
447
448
{
   headerItem()->setText(0,title);
}

///Select an item in the TreeView
bool CallView::selectItem(Call* item) 
{
449
450
   if (SFLPhone::model()->getIndex(item)) {
      setCurrentItem(SFLPhone::model()->getIndex(item));
451
452
453
454
455
456
457
458
459
      return true;
   }
   else
      return false;
}

///Return the current item
Call* CallView::getCurrentItem() 
{
460
461
   if (currentItem() && SFLPhone::model()->getCall(QTreeWidget::currentItem()))
      return SFLPhone::model()->getCall(QTreeWidget::currentItem());
462
463
464
465
466
467
468
   else
      return false;
}

///Remove a TreeView item and delete it
bool CallView::removeItem(Call* item) 
{
469
470
   if (indexOfTopLevelItem(SFLPhone::model()->getIndex(item)) != -1) {//TODO To remove once safe
     removeItemWidget(SFLPhone::model()->getIndex(item),0);
471
472
473
474
475
476
477
478
479
480
481
482
483
     return true;
   }
   else
      return false;
}

///Return the TreeView, this
QWidget* CallView::getWidget() 
{
   return this;
}

///Convenience wrapper around extractItem(QTreeWidgetItem*)
484
QTreeWidgetItem* CallView::extractItem(const QString& callId) 
485
{
486
   QTreeWidgetItem* currentItem = SFLPhone::model()->getIndex(callId);
487
488
489
490
491
492
493
494
495
496
   return extractItem(currentItem);
}

///Extract an item from the TreeView and return it, the item is -not- deleted
QTreeWidgetItem* CallView::extractItem(QTreeWidgetItem* item) 
{
   QTreeWidgetItem* parentItem = item->parent();
   
   if (parentItem) {
      if ((indexOfTopLevelItem(parentItem) == -1 ) || (parentItem->indexOfChild(item) == -1)) {
497
         kDebug() << "The conversation does not exist";
498
499
500
501
502
503
504
505
506
507
508
509
510
511
         return 0;
      }
      
      QTreeWidgetItem* toReturn = parentItem->takeChild(parentItem->indexOfChild(item));

      return toReturn;
   }
   else
      return takeTopLevelItem(indexOfTopLevelItem(item));
}

///Convenience wrapper around insertItem(QTreeWidgetItem*, QTreeWidgetItem*)
CallTreeItem* CallView::insertItem(QTreeWidgetItem* item, Call* parent) 
{
512
   return insertItem(item,(parent)?SFLPhone::model()->getIndex(parent):0);
513
514
515
516
517
518
}

///Insert a TreeView item in the TreeView as child of parent or as a top level item, also restore the item Widget
CallTreeItem* CallView::insertItem(QTreeWidgetItem* item, QTreeWidgetItem* parent) 
{
   if (!item) {
519
      kDebug() << "This is not a valid call";
520
521
522
523
524
525
526
527
528
      return 0;
   }
   
   if (!parent)
      insertTopLevelItem(0,item);
   else
      parent->addChild(item);
   
   CallTreeItem* callItem = new CallTreeItem();
529
530
531
532
533
   connect(callItem, SIGNAL(showChilds(CallTreeItem*)), this, SLOT(showDropOptions(CallTreeItem*)));
   connect(callItem, SIGNAL(askTransfer(Call*)), this, SLOT(showTransferOverlay(Call*)));
   connect(callItem, SIGNAL(transferDropEvent(Call*,QMimeData*)), this, SLOT(transferDropEvent(Call*,QMimeData*)));
   connect(callItem, SIGNAL(conversationDropEvent(Call*,QMimeData*)), this, SLOT(conversationDropEvent(Call*,QMimeData*)));
   
534
535
   SFLPhone::model()->updateWidget(SFLPhone::model()->getCall(item), callItem);
   callItem->setCall(SFLPhone::model()->getCall(item));
536
537
538
539
540
541
542
543
544
545
   
   setItemWidget(item,0,callItem);
   
   expandAll();
   return callItem;
}

///Remove a call from the interface
void CallView::destroyCall(Call* toDestroy) 
{
546
   if (SFLPhone::model()->getIndex(toDestroy) == currentItem())
547
548
      setCurrentItem(0);
   
549
   if (!SFLPhone::model()->getIndex(toDestroy))
550
       kDebug() << "Call not found";
551
552
553
554
   else if (indexOfTopLevelItem(SFLPhone::model()->getIndex(toDestroy)) != -1)
      takeTopLevelItem(indexOfTopLevelItem(SFLPhone::model()->getIndex(toDestroy)));
   else if (SFLPhone::model()->getIndex(toDestroy)->parent()) //May crash here
      SFLPhone::model()->getIndex(toDestroy)->parent()->removeChild(SFLPhone::model()->getIndex(toDestroy));
555
   else
556
      kDebug() << "Call not found";
557
558
559
560
561
}

/// @todo Remove the text partially covering the TreeView item widget when it is being dragged, a beter implementation is needed
void CallView::clearArtefact(QTreeWidgetItem* item) 
{
562
563
   if (item)
      item->setText(0,"");
564
565
566
567
568
569
570
571
572
573
574
}


/*****************************************************************************
 *                                                                           *
 *                           Event related code                              *
 *                                                                           *
 ****************************************************************************/

void CallView::itemDoubleClicked(QTreeWidgetItem* item, int column) {
   Q_UNUSED(column)
575
   kDebug() << "Item doubleclicked" << SFLPhone::model()->getCall(item)->getState();
576
577
578
579
   switch(SFLPhone::model()->getCall(item)->getState()) {
      case CALL_STATE_INCOMING:
         SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_ACCEPT);
         break;
580
      case CALL_STATE_HOLD:
581
         SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_HOLD);
582
583
         break;
      case CALL_STATE_DIALING:
584
         SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_ACCEPT);
585
586
         break;
      default:
587
         kDebug() << "Double clicked an item with no action on double click.";
588
589
590
591
592
    }
}

void CallView::itemClicked(QTreeWidgetItem* item, int column) {
   Q_UNUSED(column)
593
   emit itemChanged(SFLPhone::model()->getCall(item));
594
   kDebug() << "Item clicked";
595
596
597
598
599
600
601
602
603
604
}


/*****************************************************************************
 *                                                                           *
 *                         Conference related code                           *
 *                                                                           *
 ****************************************************************************/

///Add a new conference, get the call list and update the interface as needed
605
Call* CallView::addConference(Call* conf) 
606
{
607
   kDebug() << "Conference created";
608
   Call* newConf =  conf;//SFLPhone::model()->addConference(confID);//TODO ELV?
609
610
   
   QTreeWidgetItem* confItem = new QTreeWidgetItem();
611
   SFLPhone::model()->updateIndex(conf,confItem);
Emmanuel Lepage's avatar
Emmanuel Lepage committed
612

613
   insertItem(confItem,(QTreeWidgetItem*)0);
Emmanuel Lepage's avatar
Emmanuel Lepage committed
614

615
616
617
618
   
   setCurrentItem(confItem);

   CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
619
   QStringList callList = callManager.getParticipantList(conf->getConfId());
620
621
   
   foreach (QString callId, callList) {
622
      kDebug() << "Adding " << callId << "to the conversation";
623
      insertItem(extractItem(SFLPhone::model()->getIndex(callId)),confItem);
624
625
626
627
628
629
630
   }
   
   Q_ASSERT_X(confItem->childCount() == 0, "add conference","Conference created, but without any participants");
   return newConf;
}

///Executed when the daemon signal a modification in an existing conference. Update the call list and update the TreeView
631
bool CallView::conferenceChanged(Call* conf) 
632
{
633
   kDebug() << "Conference changed";
634
635
   //if (!SFLPhone::model()->conferenceChanged(confId, state))
   //  return false;
636
637

   CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
638
   QStringList callList = callManager.getParticipantList(conf->getConfId());
639
640
641

   QList<QTreeWidgetItem*> buffer;
   foreach (QString callId, callList) {
642
643
644
645
      if (SFLPhone::model()->getCall(callId)) {
         QTreeWidgetItem* item3 = extractItem(SFLPhone::model()->getIndex(callId));
         insertItem(item3, SFLPhone::model()->getIndex(conf));
         buffer << SFLPhone::model()->getIndex(callId);
646
647
      }
      else
648
         kDebug() << "Call " << callId << " does not exist";
649
650
   }

651
652
653
654
655
   if (SFLPhone::model()->getIndex(conf)) /*Can happen is the daemon crashed*/
      for (int j =0; j < SFLPhone::model()->getIndex(conf)->childCount();j++) {
         if (buffer.indexOf(SFLPhone::model()->getIndex(conf)->child(j)) == -1)
            insertItem(extractItem(SFLPhone::model()->getIndex(conf)->child(j)));
      }
656
   
657
   Q_ASSERT_X(SFLPhone::model()->getIndex(conf)->childCount() == 0,"changind conference","A conference can't have no participants");
658
659
660
661
662
   
   return true;
}

///Remove a conference from the model and the TreeView
663
void CallView::conferenceRemoved(Call* conf) 
664
{
665
   kDebug() << "Attempting to remove conference";
666
667
668
669
   QTreeWidgetItem* idx = SFLPhone::model()->getIndex(conf);
   if (idx) {
   while (idx->childCount()) {
      insertItem(extractItem(SFLPhone::model()->getIndex(conf)->child(0)));
670
   }
671
672
   takeTopLevelItem(indexOfTopLevelItem(SFLPhone::model()->getIndex(conf)));
   //SFLPhone::model()->conferenceRemoved(confId);
673
   kDebug() << "Conference removed";
674
675
   }
   else {
676
      kDebug() << "Conference not found";
677
   }
678
679
680
681
682
}

///Clear the list of old calls //TODO Clear them from the daemon
void CallView::clearHistory()
{
683
   //SFLPhone::model()->getHistory().clear();
684
685
}

686
687
688
689
///Redirect keypresses to parent
void CallView::keyPressEvent(QKeyEvent* event) {
   SFLPhone::app()->view()->keyPressEvent(event);
}