/* * 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(); // mChatRoomModel = nullptr; // mConferenceModel = nullptr; } 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(); add(*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; qDebug() << "[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 { auto testAddress = ToolModel::interpretUrl(address); bool exists = false; for (auto itParticipant = mList.begin(); !exists && itParticipant != mList.end(); ++itParticipant) exists = testAddress->weakEqual( ToolModel::interpretUrl(itParticipant->objectCast()->getSipAddress())); return exists; } // void ParticipantList::updateParticipants() { // if (/*mChatRoomModel ||*/ mConferenceModel) { // bool changed = false; // mConferenceModel->getMonitor()->getParticipantList(); // // auto dbParticipants = (/*mChatRoomModel ? mChatRoomModel->getParticipants() :*/ mConferenceModel->get()); // // Remove left participants // auto itParticipant = mList.begin(); // while (itParticipant != mList.end()) { // auto itDbParticipant = dbParticipants.begin(); // while ( // itDbParticipant != dbParticipants.end() && // (itParticipant->objectCast()->getParticipant() && // !(*itDbParticipant) // ->getAddress() // ->weakEqual(itParticipant->objectCast()->getParticipant()->getAddress()) || // !itParticipant->objectCast()->getParticipant() && // !(*itDbParticipant) // ->getAddress() // ->weakEqual( // Utils::interpretUrl(itParticipant->objectCast()->getSipAddress())))) { // ++itDbParticipant; // } // if (itDbParticipant == dbParticipants.end()) { // int row = itParticipant - mList.begin(); // if (!changed) emit layoutAboutToBeChanged(); // beginRemoveRows(QModelIndex(), row, row); // itParticipant = mList.erase(itParticipant); // endRemoveRows(); // changed = true; // } else ++itParticipant; // } // // Add new // for (auto dbParticipant : dbParticipants) { // auto itParticipant = mList.begin(); // while (itParticipant != mList.end() && // ((itParticipant->objectCast()->getParticipant() && // !dbParticipant->getAddress()->weakEqual( // itParticipant->objectCast()->getParticipant()->getAddress())) // || (!itParticipant->objectCast()->getParticipant() && // !dbParticipant->getAddress()->weakEqual( // Utils::interpretUrl(itParticipant->objectCast()->getSipAddress()))))) { // ++itParticipant; // } // if (itParticipant == mList.end()) { // auto participant = QSharedPointer::create(dbParticipant); // add(participant); // changed = true; // } else if (!itParticipant->objectCast()->getParticipant() || // itParticipant->objectCast()->getParticipant() != dbParticipant) { // itParticipant->objectCast()->setParticipant(dbParticipant); // changed = true; // } // } // if (changed) { // emit layoutChanged(); // emit participantsChanged(); // emit countChanged(); // } // } // } // void ParticipantList::add(QSharedPointer participant) { // int row = mList.count(); // connect(this, &ParticipantList::deviceSecurityLevelChanged, participant.get(), // &ParticipantCore::onDeviceSecurityLevelChanged); // connect(this, &ParticipantList::securityLevelChanged, participant.get(), &ParticipantCore::onSecurityLevelChanged); // connect(participant.get(), &ParticipantCore::updateAdminStatus, this, &ParticipantList::setAdminStatus); // ProxyListModel::add(participant); // emit participantsChanged(); // } // void ParticipantList::add(const std::shared_ptr &participant) { // updateParticipants(); // } // void ParticipantList::add(const std::shared_ptr &participantAddress) { // add((mChatRoomModel ? mChatRoomModel->getChatRoom()->findParticipant(participantAddress->clone()) // : mConferenceModel->getConference()->findParticipant(participantAddress))); // } 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 (mChatRoomModel && mChatRoomModel->getChatRoom()) { // Invite and wait for its creation // participant->startInvitation(); // mChatRoomModel->getChatRoom()->addParticipant(Utils::interpretUrl(address)); // } 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); }); // else { // runningCallsToAdd.push_back(*haveCall); // mConferenceModel->addParticipants(runningCallsToAdd); // } /* std::list> addressesToInvite; addressesToInvite.push_back(addressToInvite); auto callParameters = CoreManager::getInstance()->getCore()->createCallParams(mConferenceModel->getConference()->getCall()); mConferenceModel->getConference()->inviteParticipants(addressesToInvite, callParameters);*/ } emit participant->lStartInvitation(); emit countChanged(); // emit addressAdded(address); } } // const QSharedPointer // ParticipantList::getParticipant(const std::shared_ptr &address) const { // if (address) { // auto itParticipant = // std::find_if(mList.begin(), mList.end(), [address](const QSharedPointer &participant) { // return // participant.objectCast()->getParticipant()->getAddress()->weakEqual(address); // }); // if (itParticipant == mList.end()) return nullptr; // else return itParticipant->objectCast(); // } else return nullptr; // } // const QSharedPointer // ParticipantList::getParticipant(const std::shared_ptr &pParticipant) const { // if (pParticipant) { // auto itParticipant = // std::find_if(mList.begin(), mList.end(), [pParticipant](const QSharedPointer &participant) { // return participant.objectCast()->getParticipant() == pParticipant; // }); // if (itParticipant == mList.end()) return nullptr; // else return itParticipant->objectCast(); // } else return nullptr; // } //------------------------------------------------------------- // void ParticipantList::setAdminStatus(const std::shared_ptr participant, const bool // &isAdmin) { // // if (mChatRoomModel) mChatRoomModel->getChatRoom()->setParticipantAdminStatus(participant, isAdmin); // // if (mConferenceModel) mConferenceModel->getConference()->setParticipantAdminStatus(participant, isAdmin); // } // void ParticipantList::onSecurityEvent(const std::shared_ptr &eventLog) { // auto address = eventLog->getParticipantAddress(); // if (address) { // // auto participant = getParticipant(address); // // if (participant) { // // emit participant->securityLevelChanged(); // // } // } else { // address = eventLog->getDeviceAddress(); // // Looping on all participant ensure to get all devices. Can be optimized if Device address is unique : Gain // // 2n operations. // if (address) emit deviceSecurityLevelChanged(address); // } // } // void ParticipantList::onConferenceJoined() { // // updateParticipants(); // } // void ParticipantList::onParticipantAdded(const std::shared_ptr &eventLog) { // qDebug() << "onParticipantAdded event: " << eventLog->getParticipantAddress()->asString().c_str(); // // add(eventLog->getParticipantAddress()); // } // void ParticipantList::onParticipantAdded(const std::shared_ptr &participant) { // qDebug() << "onParticipantAdded part: " << participant->getAddress()->asString().c_str(); // // add(participant); // } // void ParticipantList::onParticipantAdded(const std::shared_ptr &address) { // qDebug() << "onParticipantAdded addr: " << address->asString().c_str(); // // add(address); // } // void ParticipantList::onParticipantRemoved(const std::shared_ptr &eventLog) { // onParticipantRemoved(eventLog->getParticipantAddress()); // } // void ParticipantList::onParticipantRemoved(const std::shared_ptr &participant) { // // auto p = getParticipant(participant); // // if (p) remove(p.get()); // } // void ParticipantList::onParticipantRemoved(const std::shared_ptr &address) { // // auto participant = getParticipant(address); // // if (participant) remove(participant.get()); // } // void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr &eventLog) // { onParticipantAdminStatusChanged(eventLog->getParticipantAddress()); // } // void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr // &participant) { // // auto p = getParticipant(participant); // // if (participant) emit p->adminStatusChanged(); // Request to participant to update its status from its data // } // void ParticipantList::onParticipantAdminStatusChanged(const std::shared_ptr &address) { // // auto participant = getParticipant(address); // // if (participant) // // emit participant->adminStatusChanged(); // Request to participant to update its status from its data // } // void ParticipantList::onParticipantDeviceAdded(const std::shared_ptr &eventLog) { // // auto participant = getParticipant(eventLog->getParticipantAddress()); // // if (participant) { // // emit participant->deviceCountChanged(); // // } // } // void ParticipantList::onParticipantDeviceRemoved(const std::shared_ptr &eventLog) { // // auto participant = getParticipant(eventLog->getParticipantAddress()); // // if (participant) { // // emit participant->deviceCountChanged(); // // } // } // void ParticipantList::onParticipantRegistrationSubscriptionRequested( // const std::shared_ptr &participantAddress) { // } // void ParticipantList::onParticipantRegistrationUnsubscriptionRequested( // const std::shared_ptr &participantAddress) { // } // void ParticipantList::onStateChanged() { // // if (mConferenceModel) { // // if (mConferenceModel->getConference()->getState() == linphone::Conference::State::Created) { // // updateParticipants(); // // } // // } // }