blob: ee4dd34097c47e5a5cb2fc0779cf94cfa0c6ad8e [file] [log] [blame]
/***************************************************************************
* Copyright (C) 2015 by Savoir-Faire Linux *
* Author: Edric Ladent Milaret <edric.ladent-milaret@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, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "callwidget.h"
#include "ui_callwidget.h"
#include <memory>
#include "audio/settings.h"
#include "personmodel.h"
#include "fallbackpersoncollection.h"
#include "categorizedcontactmodel.h"
#include "localhistorycollection.h"
#include "media/text.h"
#include "media/recording.h"
#include "media/textrecording.h"
#include "wizarddialog.h"
#include "windowscontactbackend.h"
CallWidget::CallWidget(QWidget *parent) :
NavWidget(Main ,parent),
ui(new Ui::CallWidget),
menu_(new QMenu())
{
ui->setupUi(this);
ui->callInvite->setVisible(false);
ui->videoWidget->setVisible(false);
setActualCall(nullptr);
videoRenderer_ = nullptr;
connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)),
ui->instantMessagingWidget, SLOT(setVisible(bool)));
ui->spinnerWidget->hide();
spinner_ = new QMovie(":/images/spinner.gif");
if (spinner_->isValid()) {
ui->spinnerLabel->setMovie(spinner_);
}
try {
callModel_ = CallModel::instance();
connect(callModel_, SIGNAL(incomingCall(Call*)),
this, SLOT(callIncoming(Call*)));
connect(callModel_, SIGNAL(callAdded(Call*,Call*)),
this, SLOT(addedCall(Call*, Call*)));
connect(callModel_, SIGNAL(callStateChanged(Call*, Call::State)),
this, SLOT(callStateChanged(Call*, Call::State)));
connect(AccountModel::instance(),
SIGNAL(accountStateChanged(Account*,Account::RegistrationState)),
this,
SLOT(checkRegistrationState(Account*,Account::RegistrationState)));
connect(AccountModel::instance()
, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>))
, this
, SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));
ui->callList->setModel(callModel_);
ui->callList->setSelectionModel(callModel_->selectionModel());
CategorizedHistoryModel::instance()->
addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
PersonModel::instance()->
addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED);
PersonModel::instance()->
addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);
ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
ui->historyList->setHeaderHidden(true);
historyDelegate_ = new HistoryDelegate();
ui->historyList->setItemDelegate(historyDelegate_);
connect(CategorizedHistoryModel::SortedProxy::instance()->model(), &QSortFilterProxyModel::layoutChanged, [=]() {
auto idx = CategorizedHistoryModel::SortedProxy::instance()->model()->index(0,0);
if (idx.isValid())
ui->historyList->setExpanded(idx, true);
});
ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel());
CategorizedContactModel::instance()->setSortAlphabetical(false);
ui->contactView->setModel(CategorizedContactModel::instance());
contactDelegate_ = new ContactDelegate();
ui->contactView->setItemDelegate(contactDelegate_);
findRingAccount();
} catch (...) {
qDebug() << "INIT ERROR";
}
}
CallWidget::~CallWidget()
{
delete ui;
delete spinner_;
delete menu_;
delete historyDelegate_;
delete contactDelegate_;
}
void
CallWidget::findRingAccount(QModelIndex idx1, QModelIndex idx2, QVector<int> vec)
{
Q_UNUSED(idx1)
Q_UNUSED(idx2)
Q_UNUSED(vec)
auto a_count = AccountModel::instance()->rowCount();
auto found = false;
for (int i = 0; i < a_count; ++i) {
auto idx = AccountModel::instance()->index(i, 0);
auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
auto username = idx.data(static_cast<int>(Account::Role::Username));
ui->ringIdLabel->setText(
"Your Ring ID: " + username.toString());
found = true;
return;
}
}
if (not found){
ui->ringIdLabel->setText("NO RING ACCOUNT FOUND");
}
}
void
CallWidget::checkRegistrationState(Account *account,
Account::RegistrationState state)
{
Q_UNUSED(account);
QPixmap pm(20,20);
pm.fill();
QPainter p(&pm);
QPen pen(Qt::black, 2);
p.setPen(pen);
p.setRenderHint(QPainter::Antialiasing, true);
switch(state) {
case Account::RegistrationState::ERROR:
p.setBrush(Qt::red);
break;
case Account::RegistrationState::TRYING:
p.setBrush(Qt::yellow);
break;
case Account::RegistrationState::READY:
{
p.setBrush(Qt::green);
auto a_count = AccountModel::instance()->rowCount();
for (int i = 0; i < a_count; ++i) {
auto idx = AccountModel::instance()->index(i, 0);
auto stateAcc = idx.data(
static_cast<int>(Account::Role::RegistrationState));
if (stateAcc.value<Account::RegistrationState>()
!= Account::RegistrationState::READY) {
checkRegistrationState(nullptr,
stateAcc.value<Account::RegistrationState>());
return;
}
}
}
break;
default:
break;
}
p.drawEllipse(3, 3, 16, 16);
ui->accountStateHintLabel->setPixmap(pm);
ui->accountStateHintLabel->show();
}
void
CallWidget::findRingAccount()
{
auto a_count = AccountModel::instance()->rowCount();
auto found = false;
for (int i = 0; i < a_count; ++i) {
auto idx = AccountModel::instance()->index(i, 0);
auto protocol = idx.data(static_cast<int>(Account::Role::Proto));
if ((Account::Protocol)protocol.toUInt() == Account::Protocol::RING) {
auto account = AccountModel::instance()->getAccountByModelIndex(idx);
if (account->displayName().isEmpty())
account->displayName() = account->alias();
auto username = account->username();
ui->ringIdLabel->setText(
"Your Ring ID: " + username);
found = true;
return;
}
}
if (!found) {
WizardDialog *wizardDialog = new WizardDialog();
wizardDialog->exec();
delete wizardDialog;
}
}
void
CallWidget::callIncoming(Call *call)
{
if (!call->account()->isAutoAnswer()) {
ui->callLabel->setText("Call from " + call->formattedName());
ui->callInvite->setVisible(true);
ui->callInvite->raise();
}
setActualCall(call);
}
void
CallWidget::on_acceptButton_clicked()
{
if (actualCall_ != nullptr)
actualCall_->performAction(Call::Action::ACCEPT);
ui->callInvite->setVisible(false);
}
void
CallWidget::on_refuseButton_clicked()
{
if (actualCall_ == nullptr)
return;
actualCall_->performAction(Call::Action::REFUSE);
setActualCall(nullptr);
ui->callInvite->setVisible(false);
}
void
CallWidget::addedCall(Call* call, Call* parent) {
Q_UNUSED(parent);
if (call->direction() == Call::Direction::OUTGOING) {
displaySpinner(true);
setActualCall(call);
}
}
void
CallWidget::callStateChanged(Call* call, Call::State previousState)
{
Q_UNUSED(previousState)
if (call == nullptr)
return;
ui->callList->setCurrentIndex(callModel_->getIndex(actualCall_));
if (call->state() == Call::State::OVER
|| call->state() == Call::State::ERROR
|| call->state() == Call::State::FAILURE
|| call->state() == Call::State::ABORTED) {
setActualCall(nullptr);
ui->videoWidget->hide();
displaySpinner(false);
auto onHoldCall = callModel_->getActiveCalls().first();
if (onHoldCall != nullptr && onHoldCall->state() == Call::State::HOLD) {
setActualCall(onHoldCall);
onHoldCall->performAction(Call::Action::HOLD);
}
} else if (call->state() == Call::State::HOLD) {
ui->videoWidget->hide();
} else if (call->state() == Call::State::CURRENT) {
displaySpinner(false);
ui->videoWidget->show();
}
ui->callStateLabel->setText("Call State : " + call->toHumanStateName());
}
void
CallWidget::on_callList_activated(const QModelIndex &index)
{
Call *callSelected = callModel_->getCall(index);
if (actualCall_ != nullptr) {
if (callSelected == actualCall_)
return;
ui->videoWidget->hide();
actualCall_->performAction(Call::Action::HOLD);
}
setActualCall(callSelected);
actualCall_->performAction(Call::Action::HOLD);
ui->videoWidget->show();
}
void
CallWidget::atExit() {
}
void
CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
{
QString uri;
auto var = index.child(0,0).data(
static_cast<int>(Person::Role::Object));
if (var.isValid()) {
Person* person = var.value<Person*>();
if (person->phoneNumbers().size() > 0) {
uri = person->phoneNumbers().at(0)->uri();
}
}
if (not uri.isEmpty()) {
auto outCall = CallModel::instance()->dialingCall(uri);
outCall->setDialNumber(uri);
outCall->performAction(Call::Action::ACCEPT);
}
}
void
CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
{
if (not index.isValid())
return;
QString number = index.model()->data(index, static_cast<int>(Call::Role::Number)).toString();
if (not number.isEmpty()) {
auto outCall = CallModel::instance()->dialingCall(number);
outCall->setDialNumber(number);
outCall->performAction(Call::Action::ACCEPT);
}
}
void
CallWidget::setActualCall(Call* value)
{
actualCall_ = value;
ui->instantMessagingWidget->setMediaText(actualCall_);
}
void
CallWidget::on_sortComboBox_currentIndexChanged(int index)
{
auto idx = CategorizedHistoryModel::SortedProxy::instance()->
categoryModel()->index(index, 0);
CategorizedHistoryModel::SortedProxy::instance()->categorySelectionModel()->
setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
}
void
CallWidget::displaySpinner(bool display)
{
display ? ui->spinnerWidget->show() : ui->spinnerWidget->hide();
if (ui->spinnerLabel->movie())
display ? ui->spinnerLabel->movie()->start() : ui->spinnerLabel->movie()->stop();
}
void CallWidget::on_cancelButton_clicked()
{
if (actualCall_)
actualCall_->performAction(Call::Action::REFUSE);
}