blob: 3293b7efef9ca5a26096ee0f84d675a0c6706152 [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 Milaret53ac6e52015-09-14 13:37:06 -0400174 QString("%1: %2").arg(tr("Your RingID"), 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 Milaret53ac6e52015-09-14 13:37:06 -0400244 QString("%1: %2").arg(tr("Your RingID"), 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 Milaret53ac6e52015-09-14 13:37:06 -0400260 ui->callLabel->setText(QString("%1 %2").arg(tr("Call from"), call->formattedName()));
Edric Milaret627500d2015-03-27 16:41:40 -0400261 ui->callInvite->setVisible(true);
Edric Milaret435cdfc2015-06-01 16:15:50 -0400262 ui->callInvite->raise();
263 }
Edric Milaret6456baa2015-05-21 12:18:07 -0400264 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400265}
266
267void
268CallWidget::on_acceptButton_clicked()
269{
270 if (actualCall_ != nullptr)
Edric Milaret53f57b62015-05-11 11:02:17 -0400271 actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret627500d2015-03-27 16:41:40 -0400272 ui->callInvite->setVisible(false);
273}
274
275void
276CallWidget::on_refuseButton_clicked()
277{
278 if (actualCall_ == nullptr)
279 return;
280 actualCall_->performAction(Call::Action::REFUSE);
Edric Milaret6456baa2015-05-21 12:18:07 -0400281 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400282 ui->callInvite->setVisible(false);
283}
284
285void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400286CallWidget::addedCall(Call* call, Call* parent)
287{
Edric Milaret627500d2015-03-27 16:41:40 -0400288 Q_UNUSED(parent);
289 if (call->direction() == Call::Direction::OUTGOING) {
Edric Milaretc7ab5502015-06-15 11:18:02 -0400290 displaySpinner(true);
Edric Milaret6456baa2015-05-21 12:18:07 -0400291 setActualCall(call);
Edric Milaret627500d2015-03-27 16:41:40 -0400292 }
293}
294
295void
Edric Milaret67007d12015-05-07 09:40:09 -0400296CallWidget::callStateChanged(Call* call, Call::State previousState)
297{
Edric Milaret627500d2015-03-27 16:41:40 -0400298 Q_UNUSED(previousState)
Edric Milaretb5b49072015-05-08 11:56:07 -0400299 if (call == nullptr)
300 return;
Edric Milaret627500d2015-03-27 16:41:40 -0400301 ui->callList->setCurrentIndex(callModel_->getIndex(actualCall_));
Edric Milaretc7ab5502015-06-15 11:18:02 -0400302 if (call->state() == Call::State::OVER
303 || call->state() == Call::State::ERROR
304 || call->state() == Call::State::FAILURE
305 || call->state() == Call::State::ABORTED) {
Edric Milaret6456baa2015-05-21 12:18:07 -0400306 setActualCall(nullptr);
Edric Milaret627500d2015-03-27 16:41:40 -0400307 ui->videoWidget->hide();
Edric Milaretc7ab5502015-06-15 11:18:02 -0400308 displaySpinner(false);
Edric Milaret4f630842015-06-11 16:10:29 -0400309 auto onHoldCall = callModel_->getActiveCalls().first();
Edric Milaretd8528fa2015-07-07 14:13:51 -0400310 if (onHoldCall != nullptr && onHoldCall->state() == Call::State::HOLD) {
Edric Milaret4f630842015-06-11 16:10:29 -0400311 setActualCall(onHoldCall);
312 onHoldCall->performAction(Call::Action::HOLD);
313 }
Edric Milaret53f57b62015-05-11 11:02:17 -0400314 } else if (call->state() == Call::State::CURRENT) {
Edric Milaretc7ab5502015-06-15 11:18:02 -0400315 displaySpinner(false);
Edric Milaret627500d2015-03-27 16:41:40 -0400316 ui->videoWidget->show();
Edric Milaret627500d2015-03-27 16:41:40 -0400317 }
Edric Milaret53ac6e52015-09-14 13:37:06 -0400318 ui->callStateLabel->setText(QString("%1: %2")
319 .arg(tr("Call State"), call->toHumanStateName()));
Edric Milaret627500d2015-03-27 16:41:40 -0400320}
321
322void
323CallWidget::on_callList_activated(const QModelIndex &index)
324{
325 Call *callSelected = callModel_->getCall(index);
326 if (actualCall_ != nullptr) {
327 if (callSelected == actualCall_)
328 return;
Edric Milaret72c406d2015-04-28 13:23:54 -0400329 ui->videoWidget->hide();
Edric Milaret627500d2015-03-27 16:41:40 -0400330 actualCall_->performAction(Call::Action::HOLD);
331 }
Edric Milaret6456baa2015-05-21 12:18:07 -0400332 setActualCall(callSelected);
Edric Milaret627500d2015-03-27 16:41:40 -0400333 actualCall_->performAction(Call::Action::HOLD);
Edric Milaret72c406d2015-04-28 13:23:54 -0400334 ui->videoWidget->show();
Edric Milaret627500d2015-03-27 16:41:40 -0400335}
336
337void
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400338CallWidget::atExit()
339{
Edric Milaret627500d2015-03-27 16:41:40 -0400340
341}
Edric Milaret67007d12015-05-07 09:40:09 -0400342
343void
344CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
345{
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400346 if (not index.isValid())
347 return;
348
Edric Milaret2afd2bf2015-07-21 17:12:25 -0400349 ContactMethod* uri = nullptr;
Edric Milaret67007d12015-05-07 09:40:09 -0400350
Edric Milaret7d40a4a2015-05-13 13:01:15 -0400351 auto var = index.child(0,0).data(
352 static_cast<int>(Person::Role::Object));
353 if (var.isValid()) {
354 Person* person = var.value<Person*>();
Edric Milaret2afd2bf2015-07-21 17:12:25 -0400355 if (person->phoneNumbers().size() == 1) {
356 uri = person->phoneNumbers().at(0);
357 } else if (person->phoneNumbers().size() > 1) {
358 ContactMethodPicker dlg(person->phoneNumbers());
359 auto pos = QCursor::pos();
360 dlg.move(pos.x(), pos.y());
361 if (dlg.exec())
362 uri = dlg.getSelected();
363 }
364 if (uri) {
365 auto outCall = CallModel::instance()->dialingCall(person->formattedName());
366 outCall->setDialNumber(uri);
367 outCall->performAction(Call::Action::ACCEPT);
Edric Milaret67007d12015-05-07 09:40:09 -0400368 }
369 }
Edric Milaret67007d12015-05-07 09:40:09 -0400370}
Edric Milaret53f57b62015-05-11 11:02:17 -0400371
Edric Milaret6456baa2015-05-21 12:18:07 -0400372void
373CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
Edric Milaret53f57b62015-05-11 11:02:17 -0400374{
Edric Milaret12353822015-05-14 14:41:09 -0400375 if (not index.isValid())
376 return;
377
Edric Milaret43f3c1e2015-07-16 17:52:47 -0400378 auto number = index.data(static_cast<int>(Call::Role::ContactMethod)).value<ContactMethod*>();
379 if (number) {
380 auto outCall = CallModel::instance()->dialingCall();
Edric Milaret53f57b62015-05-11 11:02:17 -0400381 outCall->setDialNumber(number);
382 outCall->performAction(Call::Action::ACCEPT);
383 }
384}
Edric Milaret6456baa2015-05-21 12:18:07 -0400385
386void
387CallWidget::setActualCall(Call* value)
388{
389 actualCall_ = value;
Edric Milaretcdc978b2015-06-04 11:25:12 -0400390 ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret12353822015-05-14 14:41:09 -0400391}
Edric Milaretcdc978b2015-06-04 11:25:12 -0400392
Edric Milaret12353822015-05-14 14:41:09 -0400393void
394CallWidget::on_sortComboBox_currentIndexChanged(int index)
395{
396 auto idx = CategorizedHistoryModel::SortedProxy::instance()->
397 categoryModel()->index(index, 0);
398 CategorizedHistoryModel::SortedProxy::instance()->categorySelectionModel()->
399 setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
400 ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
Edric Milaret6456baa2015-05-21 12:18:07 -0400401}
Edric Milaretc7ab5502015-06-15 11:18:02 -0400402
403void
404CallWidget::displaySpinner(bool display)
405{
Edric Milaretd8528fa2015-07-07 14:13:51 -0400406 display ? ui->spinnerWidget->show() : ui->spinnerWidget->hide();
Edric Milaretc7ab5502015-06-15 11:18:02 -0400407 if (ui->spinnerLabel->movie())
408 display ? ui->spinnerLabel->movie()->start() : ui->spinnerLabel->movie()->stop();
409}
Edric Milaretd8528fa2015-07-07 14:13:51 -0400410
411void CallWidget::on_cancelButton_clicked()
412{
413 if (actualCall_)
414 actualCall_->performAction(Call::Action::REFUSE);
415}