/* * Copyright (c) 2010-2020 Belledonne Communications SARL. * * This file is part of linphone-desktop * (see https://www.linphone.org). * * 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 . */ #include "ParticipantList.hpp" #include "core/App.hpp" #include "core/participant/ParticipantGui.hpp" #include "model/core/CoreModel.hpp" #include "model/tool/ToolModel.hpp" #include "tool/Utils.hpp" #include DEFINE_ABSTRACT_OBJECT(ParticipantList) QSharedPointer ParticipantList::create() { auto model = QSharedPointer(new ParticipantList(), &QObject::deleteLater); model->moveToThread(App::getInstance()->thread()); model->setSelf(model); return model; } QSharedPointer ParticipantList::create(const std::shared_ptr &conferenceModel) { auto model = create(); model->setConferenceModel(conferenceModel); return model; } ParticipantList::ParticipantList(QObject *parent) : ListProxy(parent) { App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership); } ParticipantList::~ParticipantList() { mList.clear(); } void ParticipantList::setSelf(QSharedPointer me) { if (mConferenceModelConnection) mConferenceModelConnection->disconnect(); mConferenceModelConnection = QSharedPointer>( new SafeConnection(me, mConferenceModel), &QObject::deleteLater); if (mConferenceModel) { mConferenceModelConnection->makeConnectToCore(&ParticipantList::lUpdateParticipants, [this] { mConferenceModelConnection->invokeToModel([this]() { QList> *participantList = new QList>(); mustBeInLinphoneThread(getClassName()); std::list> participants; participants = mConferenceModel->getMonitor()->getParticipantList(); for (auto it : participants) { auto model = ParticipantCore::create(it); participantList->push_back(model); } auto me = mConferenceModel->getMonitor()->getMe(); auto meModel = ParticipantCore::create(me); participantList->push_back(meModel); mConferenceModelConnection->invokeToCore([this, participantList]() { mustBeInMainThread(getClassName()); resetData(*participantList); delete participantList; }); }); }); mConferenceModelConnection->makeConnectToCore( &ParticipantList::lSetParticipantAdminStatus, [this](ParticipantCore *participant, bool status) { auto address = participant->getSipAddress(); mConferenceModelConnection->invokeToModel([this, address, status] { auto participants = mConferenceModel->getMonitor()->getParticipantList(); for (auto &participant : participants) { if (Utils::coreStringToAppString(participant->getAddress()->asStringUriOnly()) == address) { mConferenceModel->setParticipantAdminStatus(participant, status); return; } } }); }); mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantAdminStatusChanged, &ParticipantList::lUpdateParticipants); mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantAdded, &ParticipantList::lUpdateParticipants); mConferenceModelConnection->makeConnectToModel(&ConferenceModel::participantRemoved, &ParticipantList::lUpdateParticipants); } emit lUpdateParticipants(); } void ParticipantList::setConferenceModel(const std::shared_ptr &conferenceModel) { mustBeInMainThread(log().arg(Q_FUNC_INFO)); mConferenceModel = conferenceModel; lDebug() << "[ParticipantList] : set Conference " << mConferenceModel.get(); if (mConferenceModelConnection && mConferenceModelConnection->mCore.lock()) { // Unsure to get myself auto oldConnect = mConferenceModelConnection->mCore; // Setself rebuild safepointer setSelf(mConferenceModelConnection->mCore.mQData); // reset connections oldConnect.unlock(); } beginResetModel(); mList.clear(); endResetModel(); if (mConferenceModel) { emit lUpdateParticipants(); } } QVariant ParticipantList::data(const QModelIndex &index, int role) const { int row = index.row(); if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); if (role == Qt::DisplayRole) { return QVariant::fromValue(new ParticipantGui(mList[row].objectCast())); } return QVariant(); } std::list> ParticipantList::getParticipants() const { std::list> participants; for (auto participant : mList) { participants.push_back(ToolModel::interpretUrl(participant.objectCast()->getSipAddress())); } return participants; } bool ParticipantList::contains(const QString &address) const { bool exists = false; App::postModelBlock([this, address, &exists, participants = mList]() { auto testAddress = ToolModel::interpretUrl(address); for (auto itParticipant = participants.begin(); !exists && itParticipant != participants.end(); ++itParticipant) exists = testAddress->weakEqual( ToolModel::interpretUrl(itParticipant->objectCast()->getSipAddress())); }); return exists; } void ParticipantList::remove(ParticipantCore *participant) { QString address = participant->getSipAddress(); int index = 0; bool found = false; auto itParticipant = mList.begin(); while (!found && itParticipant != mList.end()) { if (itParticipant->objectCast()->getSipAddress() == address) found = true; else { ++itParticipant; ++index; } } if (found) { mConferenceModel->removeParticipant(ToolModel::interpretUrl(address)); } } void ParticipantList::addAddress(const QString &address) { if (!contains(address)) { QSharedPointer participant = QSharedPointer::create(nullptr); connect(participant.get(), &ParticipantCore::invitationTimeout, this, &ParticipantList::remove); participant->setSipAddress(address); add(participant); if (mConferenceModel) { std::list> runningCallsToAdd; mConferenceModelConnection->invokeToModel([this, address] { auto addressToInvite = ToolModel::interpretUrl(address); auto currentCalls = CoreModel::getInstance()->getCore()->getCalls(); auto haveCall = std::find_if(currentCalls.begin(), currentCalls.end(), [addressToInvite](const std::shared_ptr &call) { return call->getRemoteAddress()->weakEqual(addressToInvite); }); if (haveCall == currentCalls.end()) mConferenceModel->addParticipant(addressToInvite); }); } emit participant->lStartInvitation(); emit countChanged(); } }