/* * 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; } // ParticipantList::ParticipantList(ChatRoomModel *chatRoomModel, QObject *parent) : ProxyListModel(parent) { // if (chatRoomModel) { // mChatRoomModel = chatRoomModel; // connect(mChatRoomModel, &ChatRoomModel::securityEvent, this, &ParticipantList::onSecurityEvent); // connect(mChatRoomModel, &ChatRoomModel::conferenceJoined, this, &ParticipantList::onConferenceJoined); // connect(mChatRoomModel, &ChatRoomModel::participantAdded, this, // QOverload &>::of( // &ParticipantList::onParticipantAdded)); // connect(mChatRoomModel, &ChatRoomModel::participantRemoved, this, // QOverload &>::of( // &ParticipantList::onParticipantRemoved)); // connect(mChatRoomModel, &ChatRoomModel::participantAdminStatusChanged, this, // QOverload &>::of( // &ParticipantList::onParticipantAdminStatusChanged)); // connect(mChatRoomModel, &ChatRoomModel::participantDeviceAdded, this, // &ParticipantList::onParticipantDeviceAdded); // connect(mChatRoomModel, &ChatRoomModel::participantDeviceRemoved, this, // &ParticipantList::onParticipantDeviceRemoved); // connect(mChatRoomModel, &ChatRoomModel::participantRegistrationSubscriptionRequested, this, // &ParticipantList::onParticipantRegistrationSubscriptionRequested); // connect(mChatRoomModel, &ChatRoomModel::participantRegistrationUnsubscriptionRequested, this, // &ParticipantList::onParticipantRegistrationUnsubscriptionRequested); // updateParticipants(); // } // } // ParticipantList::ParticipantList(ConferenceModel *conferenceModel, QObject *parent) : ListProxy(parent) { // if (conferenceModel) { // mConferenceModel = conferenceModel; // connect(mConferenceModel, &ConferenceModel::participantAdded, this, // QOverload &>::of( // &ParticipantList::onParticipantAdded)); // connect(mConferenceModel, &ConferenceModel::participantRemoved, this, // QOverload &>::of( // &ParticipantList::onParticipantRemoved)); // connect(mConferenceModel, &ConferenceModel::participantAdminStatusChanged, this, // QOverload &>::of( // &ParticipantList::onParticipantAdminStatusChanged)); // connect(mConferenceModel, &ConferenceModel::conferenceStateChanged, this, // &ParticipantList::onStateChanged); // updateParticipants(); // } // } ParticipantList::ParticipantList(QObject *parent) : ListProxy(parent) { } ParticipantList::~ParticipantList() { mList.clear(); // mChatRoomModel = nullptr; // mConferenceModel = nullptr; } void ParticipantList::setSelf(QSharedPointer me) { mModelConnection = QSharedPointer>( new SafeConnection(me, mConferenceModel), &QObject::deleteLater); mModelConnection->makeConnectToCore(&ParticipantList::lUpdateParticipants, [this] { mModelConnection->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); } mModelConnection->invokeToCore([this, participantList]() { mustBeInMainThread(getClassName()); resetData(); add(*participantList); delete participantList; }); }); }); mModelConnection->makeConnectToModel(&ConferenceModel::participantAdded, &ParticipantList::lUpdateParticipants); mModelConnection->makeConnectToModel(&ConferenceModel::participantRemoved, &ParticipantList::lUpdateParticipants); 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; } QString ParticipantList::addressesToString() const { QStringList txt; for (auto item : mList) { auto participant = item.objectCast(); if (participant) { // chat room yet. txt << participant->getSipAddress(); // txt << Utils::toDisplayString(Utils::coreStringToAppString(address->asStringUriOnly()), // CoreModel::getInstance()->getSettingsModel()->getSipDisplayMode()); } } if (txt.size() > 0) txt.removeFirst(); // Remove me return txt.join(", "); } QString ParticipantList::displayNamesToString() const { QStringList txt; for (auto item : mList) { auto participant = item.objectCast(); if (participant) { QString displayName = participant->getSipAddress(); if (displayName != "") txt << displayName; } } if (txt.size() > 0) txt.removeFirst(); // Remove me return txt.join(", "); } QString ParticipantList::usernamesToString() const { QStringList txt; for (auto item : mList) { auto participant = item.objectCast(); if (participant) { auto username = participant->getDisplayName(); txt << username; } } if (txt.size() > 0) txt.removeFirst(); // Remove me return txt.join(", "); } 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)); } } // 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(); // } // } }