blob: 6afd76dd8e766c4682d8699f9a8324d62f72c47c [file] [log] [blame]
Edric Milaret627500d2015-03-27 16:41:40 -04001/***************************************************************************
Edric Milaret4bba46d2015-04-29 16:33:38 -04002 * Copyright (C) 2015 by Savoir-Faire Linux *
Edric Milaret627500d2015-03-27 16:41:40 -04003 * Author: Edric Ladent Milaret <edric.ladent-milaret@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#include "callwidget.h"
20#include "ui_callwidget.h"
21
Edric Milaret43f3c1e2015-07-16 17:52:47 -040022#include <QClipboard>
23
Edric Milaret53f57b62015-05-11 11:02:17 -040024#include <memory>
Edric Milaret627500d2015-03-27 16:41:40 -040025
Edric Milaret43f3c1e2015-07-16 17:52:47 -040026//ERROR is defined in windows.h
27#include "utils.h"
28#undef ERROR
29
Edric Milaret627500d2015-03-27 16:41:40 -040030#include "audio/settings.h"
31#include "personmodel.h"
Edric Milaret43f3c1e2015-07-16 17:52:47 -040032#include "person.h"
Edric Milaret627500d2015-03-27 16:41:40 -040033#include "fallbackpersoncollection.h"
Edric Milaret67007d12015-05-07 09:40:09 -040034#include "categorizedcontactmodel.h"
Edric Milaret6a642e22015-05-27 15:06:30 -040035#include "localhistorycollection.h"
Edric Milaret1b197eb2015-06-01 15:09:56 -040036#include "media/text.h"
37#include "media/recording.h"
38#include "media/textrecording.h"
Edric Milaret627500d2015-03-27 16:41:40 -040039
Edric Milaret559bda52015-04-29 17:02:31 -040040#include "wizarddialog.h"
Edric Milaret83b248c2015-06-02 11:42:23 -040041#include "windowscontactbackend.h"
Edric Milaret43f3c1e2015-07-16 17:52:47 -040042#include "contactpicker.h"
Edric Milaret2afd2bf2015-07-21 17:12:25 -040043#include "contactmethodpicker.h"
Edric Milaret627500d2015-03-27 16:41:40 -040044
45CallWidget::CallWidget(QWidget *parent) :
46 NavWidget(Main ,parent),
Edric Milaret7d40a4a2015-05-13 13:01:15 -040047 ui(new Ui::CallWidget),
48 menu_(new QMenu())
Edric Milaret627500d2015-03-27 16:41:40 -040049{
50 ui->setupUi(this);
51
Edric Milaret627500d2015-03-27 16:41:40 -040052 ui->callInvite->setVisible(false);
Edric Milareta9f937f2015-06-01 17:10:34 -040053 ui->videoWidget->setVisible(false);
Edric Milaret627500d2015-03-27 16:41:40 -040054
Edric Milaret6456baa2015-05-21 12:18:07 -040055 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -040056 videoRenderer_ = nullptr;
57
Edric Milaret3aca8e32015-06-12 10:01:40 -040058 connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)),
59 ui->instantMessagingWidget, SLOT(setVisible(bool)));
60
Edric Milaretd8528fa2015-07-07 14:13:51 -040061 ui->spinnerWidget->hide();
Edric Milaretc7ab5502015-06-15 11:18:02 -040062 spinner_ = new QMovie(":/images/spinner.gif");
63 if (spinner_->isValid()) {
64 ui->spinnerLabel->setMovie(spinner_);
65 }
66
Edric Milaret627500d2015-03-27 16:41:40 -040067 try {
68 callModel_ = CallModel::instance();
69
70 connect(callModel_, SIGNAL(incomingCall(Call*)),
71 this, SLOT(callIncoming(Call*)));
72 connect(callModel_, SIGNAL(callAdded(Call*,Call*)),
73 this, SLOT(addedCall(Call*, Call*)));
74 connect(callModel_, SIGNAL(callStateChanged(Call*, Call::State)),
75 this, SLOT(callStateChanged(Call*, Call::State)));
76
Edric Milarete5afb072015-06-02 16:45:44 -040077 connect(AccountModel::instance(),
78 SIGNAL(accountStateChanged(Account*,Account::RegistrationState)),
79 this,
80 SLOT(checkRegistrationState(Account*,Account::RegistrationState)));
81
Edric Milaret67007d12015-05-07 09:40:09 -040082 connect(AccountModel::instance()
83 , SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>))
84 , this
85 , SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));
86
Edric Milaret627500d2015-03-27 16:41:40 -040087 ui->callList->setModel(callModel_);
Edric Milaret029b95a2015-06-09 09:51:44 -040088 ui->callList->setSelectionModel(callModel_->selectionModel());
Edric Milaret627500d2015-03-27 16:41:40 -040089
Edric Milaretbe0aa5a2015-07-31 15:08:39 -040090 PersonModel::instance()->
Edric Milaret43f3c1e2015-07-16 17:52:47 -040091 addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
92
93 CategorizedContactModel::instance()->setSortAlphabetical(false);
94 CategorizedContactModel::instance()->setUnreachableHidden(true);
95 ui->contactView->setModel(CategorizedContactModel::instance());
96 contactDelegate_ = new ContactDelegate();
97 ui->contactView->setItemDelegate(contactDelegate_);
98
Edric Milaret627500d2015-03-27 16:41:40 -040099 CategorizedHistoryModel::instance()->
Edric Milaret6a642e22015-05-27 15:06:30 -0400100 addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
Edric Milaret627500d2015-03-27 16:41:40 -0400101
Edric Milaret12353822015-05-14 14:41:09 -0400102 ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
103 CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
Edric Milaret53f57b62015-05-11 11:02:17 -0400104 ui->historyList->setHeaderHidden(true);
Edric Milaret01f23842015-06-22 14:46:01 -0400105 historyDelegate_ = new HistoryDelegate();
106 ui->historyList->setItemDelegate(historyDelegate_);
Edric Milaret77dd6982015-07-07 16:45:41 -0400107
108 connect(CategorizedHistoryModel::SortedProxy::instance()->model(), &QSortFilterProxyModel::layoutChanged, [=]() {
109 auto idx = CategorizedHistoryModel::SortedProxy::instance()->model()->index(0,0);
110 if (idx.isValid())
111 ui->historyList->setExpanded(idx, true);
112 });
113
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400114 ui->historyList->setContextMenuPolicy(Qt::CustomContextMenu);
115 connect(ui->historyList, &QListView::customContextMenuRequested, [=](const QPoint& pos){
116 if (ui->historyList->currentIndex().parent().isValid()) {
117 QPoint globalPos = ui->historyList->mapToGlobal(pos);
118 QMenu menu;
119
120 ContactMethod* contactMethod = ui->historyList->currentIndex()
121 .data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
122
Edric Milaret53ac6e52015-09-14 13:37:06 -0400123 auto copyAction = new QAction(tr("Copy number"), this);
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400124 menu.addAction(copyAction);
125 connect(copyAction, &QAction::triggered, [=]() {
126 QApplication::clipboard()->setText(contactMethod->uri());
127 });
Edric Milaretbe0aa5a2015-07-31 15:08:39 -0400128 if (not contactMethod->contact() || contactMethod->contact()->isPlaceHolder()) {
Edric Milaret53ac6e52015-09-14 13:37:06 -0400129 auto addExisting = new QAction(tr("Add to contact"), this);
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400130 menu.addAction(addExisting);
131 connect(addExisting, &QAction::triggered, [=]() {
Edric Milaretbe0aa5a2015-07-31 15:08:39 -0400132 ContactPicker contactPicker(contactMethod);
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400133 contactPicker.move(globalPos.x(), globalPos.y() - (contactPicker.height()/2));
Edric Milaretbe0aa5a2015-07-31 15:08:39 -0400134 contactPicker.exec();
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400135 });
136 }
137 menu.exec(globalPos);
138 }
139 });
Edric Milaret53f57b62015-05-11 11:02:17 -0400140
Edric Milaret12353822015-05-14 14:41:09 -0400141 ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel());
Edric Milaret7d40a4a2015-05-13 13:01:15 -0400142
Edric Milaret627500d2015-03-27 16:41:40 -0400143 findRingAccount();
144
145 } catch (...) {
146 qDebug() << "INIT ERROR";
147 }
148}
149
150CallWidget::~CallWidget()
151{
152 delete ui;
Edric Milaretc7ab5502015-06-15 11:18:02 -0400153 delete spinner_;
154 delete menu_;
Edric Milaret01f23842015-06-22 14:46:01 -0400155 delete historyDelegate_;
156 delete contactDelegate_;
Edric Milaret627500d2015-03-27 16:41:40 -0400157}
158
159void
Edric Milaret67007d12015-05-07 09:40:09 -0400160CallWidget::findRingAccount(QModelIndex idx1, QModelIndex idx2, QVector<int> vec)
161{
162 Q_UNUSED(idx1)
163 Q_UNUSED(idx2)
164 Q_UNUSED(vec)
165
166 auto a_count = AccountModel::instance()->rowCount();
167 auto found = false;
168 for (int i = 0; i < a_count; ++i) {
169 auto idx = AccountModel::instance()->index(i, 0);
170 auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
171 if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
172 auto username = idx.data(static_cast<int>(Account::Role::Username));
173 ui->ringIdLabel->setText(
Edric Milaret1a9495d2015-09-18 10:11:32 -0400174 QString(tr("Your RingID: %1", "%1 is the RingID")).arg(username.toString()));
Edric Milaret67007d12015-05-07 09:40:09 -0400175 found = true;
176 return;
177 }
178 }
179 if (not found){
Edric Milaret53ac6e52015-09-14 13:37:06 -0400180 ui->ringIdLabel->setText(tr("NO RING ACCOUNT FOUND"));
Edric Milaret67007d12015-05-07 09:40:09 -0400181 }
182}
183
184void
Edric Milarete5afb072015-06-02 16:45:44 -0400185CallWidget::checkRegistrationState(Account *account,
186 Account::RegistrationState state)
187{
188 Q_UNUSED(account);
189
190 QPixmap pm(20,20);
191 pm.fill();
192 QPainter p(&pm);
193 QPen pen(Qt::black, 2);
194 p.setPen(pen);
195 p.setRenderHint(QPainter::Antialiasing, true);
196
197 switch(state) {
198 case Account::RegistrationState::ERROR:
199 p.setBrush(Qt::red);
200 break;
201 case Account::RegistrationState::TRYING:
202 p.setBrush(Qt::yellow);
203 break;
204 case Account::RegistrationState::READY:
Edric Milaret023e8f12015-07-07 14:52:40 -0400205 {
Edric Milarete5afb072015-06-02 16:45:44 -0400206 p.setBrush(Qt::green);
207 auto a_count = AccountModel::instance()->rowCount();
208 for (int i = 0; i < a_count; ++i) {
209 auto idx = AccountModel::instance()->index(i, 0);
210 auto stateAcc = idx.data(
211 static_cast<int>(Account::Role::RegistrationState));
212 if (stateAcc.value<Account::RegistrationState>()
213 != Account::RegistrationState::READY) {
214 checkRegistrationState(nullptr,
215 stateAcc.value<Account::RegistrationState>());
216 return;
217 }
218 }
Edric Milaret023e8f12015-07-07 14:52:40 -0400219 }
220 break;
221 default:
Edric Milarete5afb072015-06-02 16:45:44 -0400222 break;
223 }
224 p.drawEllipse(3, 3, 16, 16);
225 ui->accountStateHintLabel->setPixmap(pm);
226 ui->accountStateHintLabel->show();
227}
228
229void
Edric Milaret67007d12015-05-07 09:40:09 -0400230CallWidget::findRingAccount()
231{
Edric Milaret559bda52015-04-29 17:02:31 -0400232
Edric Milaret627500d2015-03-27 16:41:40 -0400233 auto a_count = AccountModel::instance()->rowCount();
234 auto found = false;
235 for (int i = 0; i < a_count; ++i) {
236 auto idx = AccountModel::instance()->index(i, 0);
237 auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
238 if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
Edric Milaret68779c42015-07-09 16:53:03 -0400239 auto account = AccountModel::instance()->getAccountByModelIndex(idx);
240 if (account->displayName().isEmpty())
241 account->displayName() = account->alias();
242 auto username = account->username();
Edric Milaret627500d2015-03-27 16:41:40 -0400243 ui->ringIdLabel->setText(
Edric Milaret1a9495d2015-09-18 10:11:32 -0400244 QString(tr("Your RingID: %1", "%1 is the RingID")).arg(username));
Edric Milaret627500d2015-03-27 16:41:40 -0400245 found = true;
246 return;
247 }
248 }
249 if (!found) {
Edric Milaret559bda52015-04-29 17:02:31 -0400250 WizardDialog *wizardDialog = new WizardDialog();
251 wizardDialog->exec();
252 delete wizardDialog;
Edric Milaret627500d2015-03-27 16:41:40 -0400253 }
254}
255
256void
257CallWidget::callIncoming(Call *call)
258{
Edric Milaret435cdfc2015-06-01 16:15:50 -0400259 if (!call->account()->isAutoAnswer()) {
Edric Milaret1a9495d2015-09-18 10:11:32 -0400260 ui->callLabel->setText(QString(tr("Call from %1", "%1 is the name of the caller"))
261 .arg(call->formattedName()));
Edric Milaret627500d2015-03-27 16:41:40 -0400262 ui->callInvite->setVisible(true);
Edric Milaret435cdfc2015-06-01 16:15:50 -0400263 ui->callInvite->raise();
264 }
Edric Milaret6456baa2015-05-21 12:18:07 -0400265 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400266}
267
268void
269CallWidget::on_acceptButton_clicked()
270{
271 if (actualCall_ != nullptr)
Edric Milaret53f57b62015-05-11 11:02:17 -0400272 actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret627500d2015-03-27 16:41:40 -0400273 ui->callInvite->setVisible(false);
274}
275
276void
277CallWidget::on_refuseButton_clicked()
278{
279 if (actualCall_ == nullptr)
280 return;
281 actualCall_->performAction(Call::Action::REFUSE);
Edric Milaret6456baa2015-05-21 12:18:07 -0400282 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400283 ui->callInvite->setVisible(false);
284}
285
286void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400287CallWidget::addedCall(Call* call, Call* parent)
288{
Edric Milaret627500d2015-03-27 16:41:40 -0400289 Q_UNUSED(parent);
290 if (call->direction() == Call::Direction::OUTGOING) {
Edric Milaretc7ab5502015-06-15 11:18:02 -0400291 displaySpinner(true);
Edric Milaret6456baa2015-05-21 12:18:07 -0400292 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400293 }
294}
295
296void
Edric Milaret67007d12015-05-07 09:40:09 -0400297CallWidget::callStateChanged(Call* call, Call::State previousState)
298{
Edric Milaret627500d2015-03-27 16:41:40 -0400299 Q_UNUSED(previousState)
Edric Milaretb5b49072015-05-08 11:56:07 -0400300 if (call == nullptr)
301 return;
Edric Milaret627500d2015-03-27 16:41:40 -0400302 ui->callList->setCurrentIndex(callModel_->getIndex(actualCall_));
Edric Milaretc7ab5502015-06-15 11:18:02 -0400303 if (call->state() == Call::State::OVER
304 || call->state() == Call::State::ERROR
305 || call->state() == Call::State::FAILURE
306 || call->state() == Call::State::ABORTED) {
Edric Milaret6456baa2015-05-21 12:18:07 -0400307 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400308 ui->videoWidget->hide();
Edric Milaretc7ab5502015-06-15 11:18:02 -0400309 displaySpinner(false);
Edric Milaret4f630842015-06-11 16:10:29 -0400310 auto onHoldCall = callModel_->getActiveCalls().first();
Edric Milaretd8528fa2015-07-07 14:13:51 -0400311 if (onHoldCall != nullptr && onHoldCall->state() == Call::State::HOLD) {
Edric Milaret4f630842015-06-11 16:10:29 -0400312 setActualCall(onHoldCall);
313 onHoldCall->performAction(Call::Action::HOLD);
314 }
Edric Milaret53f57b62015-05-11 11:02:17 -0400315 } else if (call->state() == Call::State::CURRENT) {
Edric Milaretc7ab5502015-06-15 11:18:02 -0400316 displaySpinner(false);
Edric Milaret627500d2015-03-27 16:41:40 -0400317 ui->videoWidget->show();
Edric Milaret627500d2015-03-27 16:41:40 -0400318 }
Edric Milaret1a9495d2015-09-18 10:11:32 -0400319 ui->callStateLabel->setText(QString(tr("Call State: %1", "%1 is the state of the call"))
320 .arg(call->toHumanStateName()));
Edric Milaret627500d2015-03-27 16:41:40 -0400321}
322
323void
324CallWidget::on_callList_activated(const QModelIndex &index)
325{
326 Call *callSelected = callModel_->getCall(index);
327 if (actualCall_ != nullptr) {
328 if (callSelected == actualCall_)
329 return;
Edric Milaret72c406d2015-04-28 13:23:54 -0400330 ui->videoWidget->hide();
Edric Milaret627500d2015-03-27 16:41:40 -0400331 actualCall_->performAction(Call::Action::HOLD);
332 }
Edric Milaret6456baa2015-05-21 12:18:07 -0400333 setActualCall(callSelected);
Edric Milaret627500d2015-03-27 16:41:40 -0400334 actualCall_->performAction(Call::Action::HOLD);
Edric Milaret72c406d2015-04-28 13:23:54 -0400335 ui->videoWidget->show();
Edric Milaret627500d2015-03-27 16:41:40 -0400336}
337
338void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400339CallWidget::atExit()
340{
Edric Milaret627500d2015-03-27 16:41:40 -0400341
342}
Edric Milaret67007d12015-05-07 09:40:09 -0400343
344void
345CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
346{
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400347 if (not index.isValid())
348 return;
349
Edric Milaret2afd2bf2015-07-21 17:12:25 -0400350 ContactMethod* uri = nullptr;
Edric Milaret67007d12015-05-07 09:40:09 -0400351
Edric Milaret7d40a4a2015-05-13 13:01:15 -0400352 auto var = index.child(0,0).data(
353 static_cast<int>(Person::Role::Object));
354 if (var.isValid()) {
355 Person* person = var.value<Person*>();
Edric Milaret2afd2bf2015-07-21 17:12:25 -0400356 if (person->phoneNumbers().size() == 1) {
357 uri = person->phoneNumbers().at(0);
358 } else if (person->phoneNumbers().size() > 1) {
359 ContactMethodPicker dlg(person->phoneNumbers());
360 auto pos = QCursor::pos();
361 dlg.move(pos.x(), pos.y());
362 if (dlg.exec())
363 uri = dlg.getSelected();
364 }
365 if (uri) {
366 auto outCall = CallModel::instance()->dialingCall(person->formattedName());
367 outCall->setDialNumber(uri);
368 outCall->performAction(Call::Action::ACCEPT);
Edric Milaret67007d12015-05-07 09:40:09 -0400369 }
370 }
Edric Milaret67007d12015-05-07 09:40:09 -0400371}
Edric Milaret53f57b62015-05-11 11:02:17 -0400372
Edric Milaret6456baa2015-05-21 12:18:07 -0400373void
374CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
Edric Milaret53f57b62015-05-11 11:02:17 -0400375{
Edric Milaret12353822015-05-14 14:41:09 -0400376 if (not index.isValid())
377 return;
378
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400379 auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
380 if (number) {
381 auto outCall = CallModel::instance()->dialingCall();
Edric Milaret53f57b62015-05-11 11:02:17 -0400382 outCall->setDialNumber(number);
383 outCall->performAction(Call::Action::ACCEPT);
384 }
385}
Edric Milaret6456baa2015-05-21 12:18:07 -0400386
387void
388CallWidget::setActualCall(Call* value)
389{
390 actualCall_ = value;
Edric Milaretcdc978b2015-06-04 11:25:12 -0400391 ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret12353822015-05-14 14:41:09 -0400392}
Edric Milaretcdc978b2015-06-04 11:25:12 -0400393
Edric Milaret12353822015-05-14 14:41:09 -0400394void
395CallWidget::on_sortComboBox_currentIndexChanged(int index)
396{
397 auto idx = CategorizedHistoryModel::SortedProxy::instance()->
398 categoryModel()->index(index, 0);
399 CategorizedHistoryModel::SortedProxy::instance()->categorySelectionModel()->
400 setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
401 ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
Edric Milaret6456baa2015-05-21 12:18:07 -0400402}
Edric Milaretc7ab5502015-06-15 11:18:02 -0400403
404void
405CallWidget::displaySpinner(bool display)
406{
Edric Milaretd8528fa2015-07-07 14:13:51 -0400407 display ? ui->spinnerWidget->show() : ui->spinnerWidget->hide();
Edric Milaretc7ab5502015-06-15 11:18:02 -0400408 if (ui->spinnerLabel->movie())
409 display ? ui->spinnerLabel->movie()->start() : ui->spinnerLabel->movie()->stop();
410}
Edric Milaretd8528fa2015-07-07 14:13:51 -0400411
412void CallWidget::on_cancelButton_clicked()
413{
414 if (actualCall_)
415 actualCall_->performAction(Call::Action::REFUSE);
416}