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

« back to all changes in this revision

Viewing changes to kde/src/callview.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
 
/***************************************************************************
2
 
 *   Copyright (C) 2009-2013 by Savoir-Faire Linux                         *
3
 
 *   Author : Emmanuel Lepage Valle <emmanuel.lepage@savoirfairelinux.com >*
4
 
 *                                                                         *
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.                                   *
9
 
 *                                                                         *
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.                          *
14
 
 *                                                                         *
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
 
 **************************************************************************/
18
 
 
19
 
//Parent
20
 
#include "callview.h"
21
 
 
22
 
//Qt
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>
30
 
 
31
 
//KDE
32
 
#include <KDebug>
33
 
#include <KLineEdit>
34
 
#include <KStandardDirs>
35
 
 
36
 
//SFLPhone library
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"
43
 
 
44
 
//sflphone
45
 
#include "sflphoneview.h"
46
 
#include "widgets/calltreeitem.h"
47
 
#include "sflphone.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"
55
 
 
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)
58
 
{
59
 
   //Widget part
60
 
   setAcceptDrops      (true );
61
 
   setDragEnabled      (true );
62
 
   setAnimated         (false);
63
 
   setUniformRowHeights(false);
64
 
   setRootIsDecorated  (false);
65
 
   setIndentation(15);
66
 
 
67
 
   CallTreeItemDelegate *delegate = new CallTreeItemDelegate(this,palette());
68
 
   setItemDelegate(delegate);
69
 
   setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
70
 
 
71
 
   QString image = "<img width=100 height=100  src='"+KStandardDirs::locate("data","sflphone-client-kde/transferarraw.png")+"' />";
72
 
 
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));
79
 
 
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;");
84
 
 
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"));
89
 
 
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 );
93
 
 
94
 
   foreach(Call* active, SFLPhone::model()->getCallList()) {
95
 
      addCall(active);
96
 
   }
97
 
 
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);
101
 
   }
102
 
 
103
 
 
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())                         );
115
 
   /*                                                                                                                                                  */
116
 
 
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);
122
 
   setPalette(p);
123
 
   setAutoFillBackground(true);
124
 
   if (!SFLPhone::model()->getCallList().size())
125
 
      TipCollection::manager()->setCurrentTip(TipCollection::dialPad());
126
 
   //END on canvas toolbar
127
 
   selectFirstItem();
128
 
} //CallView
129
 
 
130
 
///Destructor
131
 
CallView::~CallView()
132
 
{
133
 
   delete m_pTransferLE;
134
 
   if (m_pTransferOverlay) delete m_pTransferOverlay;
135
 
}
136
 
 
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
139
 
{
140
 
   Q_UNUSED(painter)
141
 
   Q_UNUSED(rect)
142
 
   Q_UNUSED(index)
143
 
}
144
 
 
145
 
 
146
 
 
147
 
/*****************************************************************************
148
 
 *                                                                           *
149
 
 *                        Drag and drop related code                         *
150
 
 *                                                                           *
151
 
 ****************************************************************************/
152
 
 
153
 
///Called when someone try to drop something on the tree
154
 
void CallView::dragEnterEvent ( QDragEnterEvent *e )
155
 
{
156
 
   kDebug() << "Potential drag event enter";
157
 
   e->accept();
158
 
}
159
 
 
160
 
///When a drag position change
161
 
void CallView::dragMoveEvent  ( QDragMoveEvent  *e )
162
 
{
163
 
   e->accept();
164
 
}
165
 
 
166
 
///When a drag event is leaving the widget
167
 
void CallView::dragLeaveEvent ( QDragLeaveEvent *e )
168
 
{
169
 
   kDebug() << "Potential drag event leave";
170
 
   e->accept();
171
 
}
172
 
 
173
 
///Proxy to handle transfer mime data
174
 
void CallView::transferDropEvent(Call* call,QMimeData* data)
175
 
{
176
 
   QByteArray encodedCallId = data->data( MIME_CALLID );
177
 
   SFLPhone::model()->attendedTransfer(SFLPhone::model()->getCall(encodedCallId),call);
178
 
}
179
 
 
180
 
///Proxy to handle conversation mime data
181
 
void CallView::conversationDropEvent(Call* call,QMimeData* data)
182
 
{
183
 
   kDebug() << "Calling real drag and drop function";
184
 
   dropMimeData(SFLPhone::model()->getIndex(call), 0, data, (Qt::DropAction)0);
185
 
}
186
 
 
187
 
///A call is dropped on another call
188
 
bool CallView::callToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
189
 
{
190
 
   Q_UNUSED(index)
191
 
   Q_UNUSED(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));
196
 
 
197
 
      if (!parent) {
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));
202
 
         }
203
 
         else
204
 
            kDebug() << "The call is not in a conversation (doing nothing)";
205
 
         return true;
206
 
      }
207
 
 
208
 
      if (SFLPhone::model()->getCall(parent)->getCallId() == QString(encodedCallId)) {
209
 
         kDebug() << "Call dropped on itself (doing nothing)";
210
 
         return true;
211
 
      }
212
 
      else if (SFLPhone::model()->getIndex(encodedCallId) == parent) {
213
 
         kDebug() << "Dropping conference on itself (doing nothing)";
214
 
         return true;
215
 
      }
216
 
 
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));
220
 
         return true;
221
 
      }
222
 
      else if ((parent->parent()) || (parent->childCount())) {
223
 
         kDebug() << "Call dropped on a conference";
224
 
 
225
 
         if (SFLPhone::model()->getIndex(encodedCallId)->childCount() && (SFLPhone::model()->getIndex(encodedCallId)->childCount()) && (!parent->childCount())) {
226
 
            kDebug() << "Conference dropped on a call (doing nothing)";
227
 
            return true;
228
 
         }
229
 
 
230
 
         QTreeWidgetItem* call1 = SFLPhone::model()->getIndex(encodedCallId);
231
 
         QTreeWidgetItem* call2 = (parent->parent())?parent->parent():parent;
232
 
 
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)";
237
 
               return true;
238
 
            }
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));
242
 
            }
243
 
            else if (call1->parent()) {
244
 
               kDebug() << "Moving call from a conference to an other";
245
 
               SFLPhone::model()->detachParticipant(SFLPhone::model()->getCall(encodedCallId));
246
 
            }
247
 
         }
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);
252
 
         }
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);
256
 
         }
257
 
         SFLPhone::model()->addParticipant(SFLPhone::model()->getCall(call1),SFLPhone::model()->getCall(call2));
258
 
         return true;
259
 
      }
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)";
262
 
         return true;
263
 
      }
264
 
 
265
 
      kDebug() << "Call dropped on another call";
266
 
      SFLPhone::model()->createConferenceFromCall(SFLPhone::model()->getCall(encodedCallId),SFLPhone::model()->getCall(parent));
267
 
      return true;
268
 
   }
269
 
   return false;
270
 
} //callToCall
271
 
 
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)
274
 
{
275
 
   Q_UNUSED(index)
276
 
   Q_UNUSED(action)
277
 
   QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
278
 
   if (!QString(encodedPhoneNumber).isEmpty()) {
279
 
      Contact* contact = AkonadiBackend::getInstance()->getContactByPhone(encodedPhoneNumber,true);
280
 
      QString name;
281
 
      name = (contact)?contact->getFormattedName():i18nc("Unknown peer","Unknown");
282
 
      Call* call2 = SFLPhone::model()->addDialingCall(name, AccountList::getCurrentAccount());
283
 
      if (call2) {
284
 
         call2->appendText(QString(encodedPhoneNumber));
285
 
         if (!parent) {
286
 
            //Dropped on free space
287
 
            kDebug() << "Adding new dialing call";
288
 
         }
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);
293
 
         }
294
 
         else {
295
 
            //Dropped on call
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);
300
 
            }
301
 
            SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
302
 
         }
303
 
      }
304
 
      else {
305
 
         HelperFunctions::displayNoAccountMessageBox(this);
306
 
      }
307
 
   }
308
 
   return false;
309
 
} //phoneNumberToCall
310
 
 
311
 
///A contact ID is dropped on a call
312
 
bool CallView::contactToCall(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action)
313
 
{
314
 
   kDebug() << "contactToCall";
315
 
   Q_UNUSED( index  )
316
 
   Q_UNUSED( action )
317
 
   QByteArray encodedContact = data->data( MIME_CONTACT );
318
 
   if (!QString(encodedContact).isEmpty()) {
319
 
      Contact* contact = AkonadiBackend::getInstance()->getContactByUid(encodedContact);
320
 
      if (contact) {
321
 
         Call* call2 = nullptr;
322
 
         if (!SFLPhone::app()->view()->selectCallPhoneNumber(&call2,contact))
323
 
            return false;
324
 
         if (!parent) {
325
 
            //Dropped on free space
326
 
            kDebug() << "Adding new dialing call";
327
 
         }
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);
332
 
         }
333
 
         else {
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);
338
 
            }
339
 
            SFLPhone::model()->createConferenceFromCall(call2,SFLPhone::model()->getCall(parent));
340
 
         }
341
 
      }
342
 
   }
343
 
   return false;
344
 
} //contactToCall
345
 
 
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)
348
 
{
349
 
   Q_UNUSED(index)
350
 
   Q_UNUSED(action)
351
 
 
352
 
   QByteArray encodedCallId      = data->data( MIME_CALLID      );
353
 
   QByteArray encodedPhoneNumber = data->data( MIME_PHONENUMBER );
354
 
   QByteArray encodedContact     = data->data( MIME_CONTACT     );
355
 
 
356
 
   if (!QString(encodedCallId).isEmpty()) {
357
 
      kDebug() << "CallId dropped"<< QString(encodedCallId);
358
 
      callToCall(parent, index, data, action);
359
 
   }
360
 
   else if (!QString(encodedPhoneNumber).isEmpty()) {
361
 
      kDebug() << "PhoneNumber dropped"<< QString(encodedPhoneNumber);
362
 
      phoneNumberToCall(parent, index, data, action);
363
 
   }
364
 
   else if (!QString(encodedContact).isEmpty()) {
365
 
      kDebug() << "Contact dropped"<< QString(encodedContact);
366
 
      contactToCall(parent, index, data, action);
367
 
   }
368
 
   clearArtefact();
369
 
   return false;
370
 
} //dropMimeData
371
 
 
372
 
///Encode data to be tranported during the drag n' drop operation
373
 
QMimeData* CallView::mimeData( const QList<QTreeWidgetItem *> items) const
374
 
{
375
 
   kDebug() << "A call is being dragged";
376
 
   if (items.size() < 1) {
377
 
      return nullptr;
378
 
   }
379
 
 
380
 
   QMimeData *mimeData = new QMimeData();
381
 
 
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());
385
 
   }
386
 
   else {
387
 
      mimeData->setData(MIME_CALLID, SFLPhone::model()->getCall(items[0])->getCallId().toAscii());
388
 
   }
389
 
 
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());
392
 
 
393
 
   CallTreeItem* widget = dynamic_cast<CallTreeItem*>(itemWidget(items[0],0));
394
 
   if (widget) {
395
 
      widget->setDragged(true);
396
 
   }
397
 
 
398
 
   return mimeData;
399
 
} //mimeData
400
 
 
401
 
 
402
 
/*****************************************************************************
403
 
 *                                                                           *
404
 
 *                            Call related code                              *
405
 
 *                                                                           *
406
 
 ****************************************************************************/
407
 
 
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)
410
 
{
411
 
   QTreeWidgetItem* callItem = new QTreeWidgetItem();
412
 
   SFLPhone::model()->updateIndex(call,callItem);
413
 
   insertItem(callItem,parent);
414
 
 
415
 
   setCurrentItem(callItem);
416
 
 
417
 
   connect(call, SIGNAL(isOver(Call*)), this, SLOT(destroyCall(Call*)));
418
 
 
419
 
   //Hack to raise call dock if it is bellow current dock
420
 
   QWidget* parW  = qobject_cast<QWidget*>(QWidget::parent());
421
 
   if (parW) {
422
 
      QWidget* parW2 = qobject_cast<QWidget*>(parW->parent());
423
 
      if (parW2) {
424
 
         QDockWidget* dock = qobject_cast<QDockWidget*>(parW2->parent());
425
 
         if (dock) {
426
 
            dock->raise();
427
 
         }
428
 
      }
429
 
   }
430
 
 
431
 
   moveCanvasTip();
432
 
   if (TipCollection::manager()->currentTip()==TipCollection::dialPad())
433
 
      TipCollection::manager()->setCurrentTip(nullptr);
434
 
 
435
 
   return call;
436
 
} //addCall
437
 
 
438
 
///Transfer a call
439
 
void CallView::transfer()
440
 
{
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()));
445
 
      }
446
 
   }
447
 
 
448
 
   m_pCallPendingTransfer = 0;
449
 
   m_pTransferLE->clear();
450
 
 
451
 
   m_pTransferOverlay->setVisible(false);
452
 
}
453
 
 
454
 
/*****************************************************************************
455
 
 *                                                                           *
456
 
 *                            View related code                              *
457
 
 *                                                                           *
458
 
 ****************************************************************************/
459
 
 
460
 
///Show the transfer overlay
461
 
void CallView::showTransferOverlay(Call* call)
462
 
{
463
 
   if (!m_pTransferOverlay) {
464
 
      kDebug() << "Creating overlay";
465
 
   }
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()));
471
 
}
472
 
 
473
 
///Is there an active overlay
474
 
bool CallView::haveOverlay()
475
 
{
476
 
   return (m_pActiveOverlay && m_pActiveOverlay->isVisible());
477
 
}
478
 
 
479
 
///Remove the active overlay
480
 
void CallView::hideOverlay()
481
 
{
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
486
 
      }
487
 
      disconnect(m_pCallPendingTransfer,SIGNAL(changed()),this,SLOT(hideOverlay()));
488
 
      m_pActiveOverlay->setVisible(false);
489
 
   }
490
 
 
491
 
   m_pActiveOverlay = 0;
492
 
 
493
 
   m_pCallPendingTransfer = 0;
494
 
} //hideOverlay
495
 
 
496
 
///Be sure the size of the overlay stay the same
497
 
void CallView::resizeEvent (QResizeEvent *e)
498
 
{
499
 
   if (m_pTransferOverlay)
500
 
      m_pTransferOverlay->resize(size());
501
 
   QTreeWidget::resizeEvent(e);
502
 
 
503
 
   if (m_pCanvasToolbar) {
504
 
      m_pCanvasToolbar->resize(width(),72);
505
 
      m_pCanvasToolbar->move(0,height()-72);
506
 
   }
507
 
}
508
 
 
509
 
///Set the TreeView header text
510
 
void CallView::setTitle(const QString& title)
511
 
{
512
 
   headerItem()->setText(0,title);
513
 
}
514
 
 
515
 
///Return the current item
516
 
Call* CallView::getCurrentItem()
517
 
{
518
 
   if (currentItem() && SFLPhone::model()->getCall(QTreeWidget::currentItem()))
519
 
      return SFLPhone::model()->getCall(QTreeWidget::currentItem());
520
 
   else
521
 
      return 0;
522
 
}
523
 
 
524
 
///Remove a TreeView item and delete it
525
 
bool CallView::removeItem(Call* item)
526
 
{
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);
532
 
      moveCanvasTip();
533
 
      return true;
534
 
   }
535
 
   else
536
 
      return false;
537
 
}
538
 
 
539
 
///Return the TreeView, this
540
 
QWidget* CallView::getWidget()
541
 
{
542
 
   return this;
543
 
}
544
 
 
545
 
///Convenience wrapper around extractItem(QTreeWidgetItem*)
546
 
QTreeWidgetItem* CallView::extractItem(const QString& callId)
547
 
{
548
 
   QTreeWidgetItem* currentItem = SFLPhone::model()->getIndex(callId);
549
 
   return extractItem(currentItem);
550
 
}
551
 
 
552
 
///Extract an item from the TreeView and return it, the item is -not- deleted
553
 
QTreeWidgetItem* CallView::extractItem(QTreeWidgetItem* item)
554
 
{
555
 
   if (!item)
556
 
      return nullptr;
557
 
   QTreeWidgetItem* parentItem = item->parent();
558
 
 
559
 
   if (parentItem) {
560
 
      if ((indexOfTopLevelItem(parentItem) == -1 ) || (parentItem->indexOfChild(item) == -1)) {
561
 
         kDebug() << "The conversation does not exist";
562
 
         return 0;
563
 
      }
564
 
 
565
 
      QTreeWidgetItem* toReturn = parentItem->takeChild(parentItem->indexOfChild(item));
566
 
 
567
 
      return toReturn;
568
 
   }
569
 
   else
570
 
      return takeTopLevelItem(indexOfTopLevelItem(item));
571
 
} //extractItem
572
 
 
573
 
///Convenience wrapper around insertItem(QTreeWidgetItem*, QTreeWidgetItem*)
574
 
CallTreeItem* CallView::insertItem(QTreeWidgetItem* item, Call* parent)
575
 
{
576
 
   return insertItem(item,(parent)?SFLPhone::model()->getIndex(parent):0);
577
 
}
578
 
 
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)
581
 
{
582
 
   if (!dynamic_cast<QTreeWidgetItem*>(item) && SFLPhone::model()->getCall(item) && !dynamic_cast<QTreeWidgetItem*>(parent))
583
 
      return nullptr;
584
 
 
585
 
   if (!item) {
586
 
      kDebug() << "This is not a valid call";
587
 
      return 0;
588
 
   }
589
 
 
590
 
   if (!parent)
591
 
      insertTopLevelItem(0,item);
592
 
   else
593
 
      parent->addChild(item);
594
 
 
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*)));
599
 
 
600
 
   SFLPhone::model()->updateWidget(SFLPhone::model()->getCall(item), callItem);
601
 
   callItem->setCall(SFLPhone::model()->getCall(item));
602
 
 
603
 
   setItemWidget(item,0,callItem);
604
 
 
605
 
   expandAll();
606
 
   return callItem;
607
 
} //insertItem
608
 
 
609
 
///Remove a call from the interface
610
 
void CallView::destroyCall(Call* toDestroy)
611
 
{
612
 
   if (SFLPhone::model()->getIndex(toDestroy) == currentItem())
613
 
      setCurrentItem(nullptr);
614
 
 
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));
626
 
      }
627
 
   }
628
 
   else
629
 
      kDebug() << "Call not found";
630
 
   moveCanvasTip();
631
 
   if (toDestroy->getState() == CALL_STATE_BUSY || toDestroy->getState() == CALL_STATE_FAILURE)
632
 
      TipCollection::manager()->setCurrentTip(TipCollection::endBusy());
633
 
   else
634
 
      TipCollection::manager()->setCurrentTip(TipCollection::endCall());
635
 
} //destroyCall
636
 
 
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()
639
 
{
640
 
   for (int i=0;i<topLevelItemCount();i++) {
641
 
      QTreeWidgetItem* item = topLevelItem(i);
642
 
      if (item) {
643
 
         CallTreeItem* widget = dynamic_cast<CallTreeItem*>(itemWidget(item,0));
644
 
         if (widget) {
645
 
            widget->setDragged(false);
646
 
         }
647
 
         for(int j=0;j< item->childCount();j++) {
648
 
            QTreeWidgetItem* item2 = item->child(j);
649
 
            CallTreeItem* widget2 = dynamic_cast<CallTreeItem*>(itemWidget(item2,0));
650
 
            if (widget2) {
651
 
               widget2->setDragged(false);
652
 
            }
653
 
         }
654
 
      }
655
 
   }
656
 
}
657
 
 
658
 
 
659
 
/*****************************************************************************
660
 
 *                                                                           *
661
 
 *                           Event related code                              *
662
 
 *                                                                           *
663
 
 ****************************************************************************/
664
 
 
665
 
///When an item is double clicked
666
 
void CallView::itemDoubleClicked(QTreeWidgetItem* item, int column) {
667
 
   Q_UNUSED(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);
672
 
         break;
673
 
      case CALL_STATE_HOLD:
674
 
         SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_HOLD);
675
 
         break;
676
 
      case CALL_STATE_DIALING:
677
 
         SFLPhone::model()->getCall(item)->actionPerformed(CALL_ACTION_ACCEPT);
678
 
         break;
679
 
      default:
680
 
         kDebug() << "Double clicked an item with no action on double click.";
681
 
    }
682
 
} //itemDoubleClicked
683
 
 
684
 
///When an item is clicked
685
 
void CallView::itemClicked(QTreeWidgetItem* item, int column) {
686
 
   Q_UNUSED(column)
687
 
   Call* call = SFLPhone::model()->getCall(item);
688
 
   call->setSelected(true);
689
 
 
690
 
   if (ConfigurationSkeleton::enableReadDetails()) {
691
 
      SFLPhoneAccessibility::getInstance()->currentCallDetails();
692
 
   }
693
 
 
694
 
   emit itemChanged(call);
695
 
   kDebug() << "Item clicked";
696
 
}
697
 
 
698
 
 
699
 
/*****************************************************************************
700
 
 *                                                                           *
701
 
 *                         Conference related code                           *
702
 
 *                                                                           *
703
 
 ****************************************************************************/
704
 
 
705
 
///Add a new conference, get the call list and update the interface as needed
706
 
Call* CallView::addConference(Call* conf)
707
 
{
708
 
   kDebug() << "Conference created";
709
 
   Call* newConf =  conf;
710
 
 
711
 
   QTreeWidgetItem* confItem = new QTreeWidgetItem();
712
 
   SFLPhone::model()->updateIndex(conf,confItem);
713
 
 
714
 
   insertItem(confItem,(QTreeWidgetItem*)0);
715
 
 
716
 
 
717
 
   setCurrentItem(confItem);
718
 
 
719
 
   CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
720
 
   const QStringList callList = callManager.getParticipantList(conf->getConfId());
721
 
 
722
 
   foreach (const QString& callId, callList) {
723
 
      kDebug() << "Adding " << callId << "to the conversation";
724
 
      insertItem(extractItem(SFLPhone::model()->getIndex(callId)),confItem);
725
 
   }
726
 
   moveCanvasTip();
727
 
   if (TipCollection::manager()->currentTip() == TipCollection::dragAndDrop()) {
728
 
      TipCollection::manager()->hideTip(TipCollection::dragAndDrop());
729
 
   }
730
 
 
731
 
   return newConf;
732
 
} //addConference
733
 
 
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)
736
 
{
737
 
   if (!dynamic_cast<Call*>(conf)) return false;
738
 
   kDebug() << "Conference changed";
739
 
 
740
 
   CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
741
 
   const QStringList callList = callManager.getParticipantList(conf->getConfId());
742
 
 
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);
749
 
      }
750
 
      else
751
 
         kDebug() << "Call " << callId << " does not exist";
752
 
   }
753
 
 
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)));
759
 
      }
760
 
 
761
 
   Q_ASSERT_X(SFLPhone::model()->getIndex(conf)->childCount() == 0,"changing conference","A conference can't have no participants");
762
 
 
763
 
   return true;
764
 
} //conferenceChanged
765
 
 
766
 
///Remove a conference from the model and the TreeView
767
 
void CallView::conferenceRemoved(Call* conf)
768
 
{
769
 
   kDebug() << "Attempting to remove conference";
770
 
   QTreeWidgetItem* idx = SFLPhone::model()->getIndex(conf);
771
 
   if (idx) {
772
 
   while (idx->childCount()) {
773
 
      insertItem(extractItem(SFLPhone::model()->getIndex(conf)->child(0)));
774
 
   }
775
 
   takeTopLevelItem(indexOfTopLevelItem(SFLPhone::model()->getIndex(conf)));
776
 
   kDebug() << "Conference removed";
777
 
   }
778
 
   else {
779
 
      kDebug() << "Conference not found";
780
 
   }
781
 
} //conferenceRemoved
782
 
 
783
 
///Clear the list of old calls //TODO Clear them from the daemon
784
 
void CallView::clearHistory()
785
 
{
786
 
   //SFLPhone::model()->getHistory().clear();
787
 
}
788
 
 
789
 
///Redirect keypresses to parent
790
 
void CallView::keyPressEvent(QKeyEvent* event) {
791
 
   SFLPhone::app()->view()->keyPressEvent(event);
792
 
}
793
 
 
794
 
///Move selection using arrow keys
795
 
void CallView::moveSelectedItem( Qt::Key direction )
796
 
{
797
 
   if (direction == Qt::Key_Left) {
798
 
      setCurrentIndex(moveCursor(QAbstractItemView::MoveLeft ,Qt::NoModifier));
799
 
   }
800
 
   else if (direction == Qt::Key_Right) {
801
 
      setCurrentIndex(moveCursor(QAbstractItemView::MoveRight,Qt::NoModifier));
802
 
   }
803
 
   else if (direction == Qt::Key_Up) {
804
 
      setCurrentIndex(moveCursor(QAbstractItemView::MoveUp   ,Qt::NoModifier));
805
 
   }
806
 
   else if (direction == Qt::Key_Down) {
807
 
      setCurrentIndex(moveCursor(QAbstractItemView::MoveDown ,Qt::NoModifier));
808
 
   }
809
 
}//moveSelectedItem
810
 
 
811
 
///Select the first call, if any
812
 
void CallView::selectFirstItem()
813
 
{
814
 
   if (model()->rowCount()) {
815
 
      QModelIndex firstItem = model()->index(0,0);
816
 
      if (model()->rowCount(firstItem) > 0) {
817
 
         firstItem = firstItem.child(0,0);
818
 
      }
819
 
      setCurrentIndex(firstItem);
820
 
   }
821
 
}
822
 
 
823
 
///Proxy to modify the background tip position
824
 
void CallView::moveCanvasTip()
825
 
{
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);
831
 
   }
832
 
   if (lastItem != QModelIndex()) {
833
 
      QRect r = visualRect(lastItem);
834
 
      topM += r.y() + r.height();
835
 
   }
836
 
 
837
 
   TipCollection::manager()->setTopMargin(topM);
838
 
   TipCollection::manager()->setBottomMargin(bottomM);
839
 
}//moveCanvasTip