callwidget.cpp 11.8 KB
Newer Older
Edric Milaret's avatar
Edric Milaret committed
1
/***************************************************************************
2
 * Copyright (C) 2015 by Savoir-Faire Linux                                *
Edric Milaret's avatar
Edric Milaret committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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"

22
#include <memory>
Edric Milaret's avatar
Edric Milaret committed
23 24 25 26

#include "audio/settings.h"
#include "personmodel.h"
#include "fallbackpersoncollection.h"
27
#include "categorizedcontactmodel.h"
Edric Milaret's avatar
Edric Milaret committed
28
#include "localhistorycollection.h"
29 30 31
#include "media/text.h"
#include "media/recording.h"
#include "media/textrecording.h"
Edric Milaret's avatar
Edric Milaret committed
32

33
#include "wizarddialog.h"
Edric Milaret's avatar
Edric Milaret committed
34
#include "windowscontactbackend.h"
Edric Milaret's avatar
Edric Milaret committed
35 36 37

CallWidget::CallWidget(QWidget *parent) :
    NavWidget(Main ,parent),
Edric Milaret's avatar
Edric Milaret committed
38 39
    ui(new Ui::CallWidget),
    menu_(new QMenu())
Edric Milaret's avatar
Edric Milaret committed
40 41 42 43
{
    ui->setupUi(this);

    ui->callInvite->setVisible(false);
Edric Milaret's avatar
Edric Milaret committed
44
    ui->videoWidget->setVisible(false);
Edric Milaret's avatar
Edric Milaret committed
45

46
    setActualCall(nullptr);
Edric Milaret's avatar
Edric Milaret committed
47 48
    videoRenderer_ = nullptr;

49 50 51
    connect(ui->videoWidget, SIGNAL(setChatVisibility(bool)),
            ui->instantMessagingWidget, SLOT(setVisible(bool)));

52
    ui->spinnerWidget->hide();
53 54 55 56 57
    spinner_ = new QMovie(":/images/spinner.gif");
    if (spinner_->isValid()) {
        ui->spinnerLabel->setMovie(spinner_);
    }

Edric Milaret's avatar
Edric Milaret committed
58 59 60 61 62 63 64 65 66 67
    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)));

68 69 70 71 72
        connect(AccountModel::instance(),
                SIGNAL(accountStateChanged(Account*,Account::RegistrationState)),
                this,
                SLOT(checkRegistrationState(Account*,Account::RegistrationState)));

73 74 75 76 77
        connect(AccountModel::instance()
                , SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>))
                , this
                , SLOT(findRingAccount(QModelIndex, QModelIndex, QVector<int>)));

Edric Milaret's avatar
Edric Milaret committed
78
        ui->callList->setModel(callModel_);
79
        ui->callList->setSelectionModel(callModel_->selectionModel());
Edric Milaret's avatar
Edric Milaret committed
80 81

        CategorizedHistoryModel::instance()->
Edric Milaret's avatar
Edric Milaret committed
82
                addCollection<LocalHistoryCollection>(LoadOptions::FORCE_ENABLED);
Edric Milaret's avatar
Edric Milaret committed
83

84 85 86 87 88 89
        PersonModel::instance()->
                addCollection<FallbackPersonCollection>(LoadOptions::FORCE_ENABLED);

        PersonModel::instance()->
                addCollection<WindowsContactBackend>(LoadOptions::FORCE_ENABLED);

Edric Milaret's avatar
Edric Milaret committed
90 91
        ui->historyList->setModel(CategorizedHistoryModel::SortedProxy::instance()->model());
        CategorizedHistoryModel::SortedProxy::instance()->model()->sort(0, Qt::DescendingOrder);
92
        ui->historyList->setHeaderHidden(true);
Edric Milaret's avatar
Edric Milaret committed
93 94
        historyDelegate_ = new HistoryDelegate();
        ui->historyList->setItemDelegate(historyDelegate_);
95 96 97 98 99 100 101

        connect(CategorizedHistoryModel::SortedProxy::instance()->model(), &QSortFilterProxyModel::layoutChanged, [=]() {
            auto idx = CategorizedHistoryModel::SortedProxy::instance()->model()->index(0,0);
            if (idx.isValid())
                ui->historyList->setExpanded(idx, true);
        });

Edric Milaret's avatar
Edric Milaret committed
102 103

        ui->sortComboBox->setModel(CategorizedHistoryModel::SortedProxy::instance()->categoryModel());
Edric Milaret's avatar
Edric Milaret committed
104

105 106
        CategorizedContactModel::instance()->setSortAlphabetical(false);
        ui->contactView->setModel(CategorizedContactModel::instance());
Edric Milaret's avatar
Edric Milaret committed
107 108
        contactDelegate_ = new ContactDelegate();
        ui->contactView->setItemDelegate(contactDelegate_);
109

Edric Milaret's avatar
Edric Milaret committed
110 111 112 113 114 115 116 117 118 119
        findRingAccount();

    } catch (...) {
        qDebug() << "INIT ERROR";
    }
}

CallWidget::~CallWidget()
{
    delete ui;
120 121
    delete spinner_;
    delete menu_;
Edric Milaret's avatar
Edric Milaret committed
122 123
    delete historyDelegate_;
    delete contactDelegate_;
Edric Milaret's avatar
Edric Milaret committed
124 125 126
}

void
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
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");
    }
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
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:
Edric Milaret's avatar
Edric Milaret committed
172
    {
173 174 175 176 177 178 179 180 181 182 183 184 185
        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;
            }
        }
Edric Milaret's avatar
Edric Milaret committed
186 187 188
    }
        break;
     default:
189 190 191 192 193 194 195
        break;
    }
    p.drawEllipse(3, 3, 16, 16);
    ui->accountStateHintLabel->setPixmap(pm);
    ui->accountStateHintLabel->show();
}

196 197 198
void
CallWidget::findRingAccount()
{
199

Edric Milaret's avatar
Edric Milaret committed
200 201 202 203 204 205 206 207 208 209 210 211 212 213
    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(
                        ui->ringIdLabel->text() + " " + username.toString());
            found = true;
            return;
        }
    }
    if (!found) {
214 215 216
        WizardDialog *wizardDialog = new WizardDialog();
        wizardDialog->exec();
        delete wizardDialog;
Edric Milaret's avatar
Edric Milaret committed
217 218 219 220 221 222
    }
}

void
CallWidget::callIncoming(Call *call)
{
Edric Milaret's avatar
Edric Milaret committed
223
    if (!call->account()->isAutoAnswer()) {
224
        ui->callLabel->setText("Call from " + call->formattedName());
Edric Milaret's avatar
Edric Milaret committed
225
        ui->callInvite->setVisible(true);
Edric Milaret's avatar
Edric Milaret committed
226 227
        ui->callInvite->raise();
    }
228
    setActualCall(call);
Edric Milaret's avatar
Edric Milaret committed
229 230 231 232 233 234
}

void
CallWidget::on_acceptButton_clicked()
{
    if (actualCall_ != nullptr)
235
        actualCall_->performAction(Call::Action::ACCEPT);
Edric Milaret's avatar
Edric Milaret committed
236 237 238 239 240 241 242 243 244
    ui->callInvite->setVisible(false);
}

void
CallWidget::on_refuseButton_clicked()
{
    if (actualCall_ == nullptr)
        return;
    actualCall_->performAction(Call::Action::REFUSE);
245
    setActualCall(nullptr);
Edric Milaret's avatar
Edric Milaret committed
246 247 248 249 250 251 252
    ui->callInvite->setVisible(false);
}

void
CallWidget::addedCall(Call* call, Call* parent) {
    Q_UNUSED(parent);
    if (call->direction() == Call::Direction::OUTGOING) {
253
        displaySpinner(true);
254
        setActualCall(call);
Edric Milaret's avatar
Edric Milaret committed
255 256 257 258
    }
}

void
259 260
CallWidget::callStateChanged(Call* call, Call::State previousState)
{
Edric Milaret's avatar
Edric Milaret committed
261
    Q_UNUSED(previousState)
262 263
    if (call == nullptr)
        return;
Edric Milaret's avatar
Edric Milaret committed
264
    ui->callList->setCurrentIndex(callModel_->getIndex(actualCall_));
265 266 267 268
    if (call->state() == Call::State::OVER
            || call->state() == Call::State::ERROR
            || call->state() == Call::State::FAILURE
            || call->state() == Call::State::ABORTED) {
269
        setActualCall(nullptr);
Edric Milaret's avatar
Edric Milaret committed
270
        ui->videoWidget->hide();
271
        displaySpinner(false);
272
        auto onHoldCall = callModel_->getActiveCalls().first();
273
        if (onHoldCall != nullptr && onHoldCall->state() == Call::State::HOLD) {
274 275 276 277 278
            setActualCall(onHoldCall);
            onHoldCall->performAction(Call::Action::HOLD);
        }
    } else if (call->state() == Call::State::HOLD) {
        ui->videoWidget->hide();
279
    } else if (call->state() == Call::State::CURRENT) {
280
        displaySpinner(false);
Edric Milaret's avatar
Edric Milaret committed
281 282
        ui->videoWidget->show();
    }
283
    ui->callStateLabel->setText("Call State : " + call->toHumanStateName());
Edric Milaret's avatar
Edric Milaret committed
284 285 286 287 288 289 290 291 292
}

void
CallWidget::on_callList_activated(const QModelIndex &index)
{
    Call *callSelected = callModel_->getCall(index);
    if (actualCall_ != nullptr) {
        if (callSelected == actualCall_)
            return;
Edric Milaret's avatar
Edric Milaret committed
293
        ui->videoWidget->hide();
Edric Milaret's avatar
Edric Milaret committed
294 295
        actualCall_->performAction(Call::Action::HOLD);
    }
296
    setActualCall(callSelected);
Edric Milaret's avatar
Edric Milaret committed
297
    actualCall_->performAction(Call::Action::HOLD);
Edric Milaret's avatar
Edric Milaret committed
298
    ui->videoWidget->show();
Edric Milaret's avatar
Edric Milaret committed
299 300 301 302 303 304
}

void
CallWidget::atExit() {

}
305 306 307 308 309 310

void
CallWidget::on_contactView_doubleClicked(const QModelIndex &index)
{
    QString uri;

Edric Milaret's avatar
Edric Milaret committed
311 312 313 314 315 316
    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();
317 318 319 320 321 322 323 324
        }
    }
    if (not uri.isEmpty()) {
        auto outCall = CallModel::instance()->dialingCall(uri);
        outCall->setDialNumber(uri);
        outCall->performAction(Call::Action::ACCEPT);
    }
}
325

326 327
void
CallWidget::on_historyList_doubleClicked(const QModelIndex &index)
328
{
Edric Milaret's avatar
Edric Milaret committed
329 330 331
    if (not index.isValid())
        return;

332 333 334 335 336 337 338
    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);
    }
}
339 340 341 342 343

void
CallWidget::setActualCall(Call* value)
{
    actualCall_ = value;
Edric Milaret's avatar
Edric Milaret committed
344
    ui->instantMessagingWidget->setMediaText(actualCall_);
Edric Milaret's avatar
Edric Milaret committed
345
}
Edric Milaret's avatar
Edric Milaret committed
346

Edric Milaret's avatar
Edric Milaret committed
347 348 349 350 351 352 353 354
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());
355
}
356 357 358 359

void
CallWidget::displaySpinner(bool display)
{
360
    display ? ui->spinnerWidget->show() : ui->spinnerWidget->hide();
361 362 363
    if (ui->spinnerLabel->movie())
        display ? ui->spinnerLabel->movie()->start() : ui->spinnerLabel->movie()->stop();
}
364 365 366 367 368 369

void CallWidget::on_cancelButton_clicked()
{
    if (actualCall_)
        actualCall_->performAction(Call::Action::REFUSE);
}