// Copyright (c) 2022 Proton AG // // This file is part of Proton Mail Bridge. // // Proton Mail Bridge 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. // // Proton Mail Bridge 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 Proton Mail Bridge. If not, see . #include "Pch.h" #include "UserList.h" #include "GRPC/GRPCClient.h" //**************************************************************************************************************************************************** /// \param[in] parent The parent object of the user list. //**************************************************************************************************************************************************** UserList::UserList(QObject *parent) : QAbstractListModel(parent) { /// \todo use mutex to prevent concurrent access } //**************************************************************************************************************************************************** // //**************************************************************************************************************************************************** void UserList::connectGRPCEvents() const { GRPCClient* client = &app().grpc(); connect(client, &GRPCClient::userChanged, this, &UserList::onUserChanged); connect(client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished); } //**************************************************************************************************************************************************** // //**************************************************************************************************************************************************** int UserList::rowCount(QModelIndex const &) const { return users_.size(); } //**************************************************************************************************************************************************** /// \param[in] index The index to retrieve data for. /// \param[in] role The role to retrieve data for. /// \return The data at the index for the given role. //**************************************************************************************************************************************************** QVariant UserList::data(QModelIndex const &index, int role) const { /// This It does not seem to be used, but the method is required by the base class. /// From the original QtThe recipe QML backend User model, the User is always returned, regardless of the role. Q_UNUSED(role) int const row = index.row(); if ((row < 0) || (row >= users_.size())) return QVariant(); return QVariant::fromValue(users_[row].get()); } //**************************************************************************************************************************************************** /// \param[in] userID The userID. /// \return the row of the user. /// \return -1 if the userID is not in the list //**************************************************************************************************************************************************** int UserList::rowOfUserID(QString const &userID) const { for (qint32 row = 0; row < users_.count(); ++row) if (userID == users_[row]->property("id")) return row; return -1; } //**************************************************************************************************************************************************** // //**************************************************************************************************************************************************** void UserList::reset() { this->beginResetModel(); users_.clear(); this->endResetModel(); } //**************************************************************************************************************************************************** /// \param[in] users The new user list. //**************************************************************************************************************************************************** void UserList::reset(QList const &users) { this->beginResetModel(); users_ = users; this->endResetModel(); } //**************************************************************************************************************************************************** /// \param[in] user The user. //**************************************************************************************************************************************************** void UserList::appendUser(SPUser const& user) { int const size = users_.size(); this->beginInsertRows(QModelIndex(), size, size); users_.append(user); this->endInsertRows(); } //**************************************************************************************************************************************************** /// \param[in] row The row. //**************************************************************************************************************************************************** void UserList::removeUserAt(int row) { if ((row < 0) && (row >= users_.size())) return; this->beginRemoveRows(QModelIndex(), row, row); users_.removeAt(row); this->endRemoveRows(); } //**************************************************************************************************************************************************** /// \param[in] row The row. /// \param[in] user The user. //**************************************************************************************************************************************************** void UserList::updateUserAtRow(int row, User const &user) { if ((row < 0) || (row >= users_.count())) { app().log().error(QString("invalid user at row %2 (user count = %2)").arg(row).arg(users_.count())); return; } users_[row]->update(user); QModelIndex modelIndex = this->index(row); emit dataChanged(modelIndex, modelIndex); } //**************************************************************************************************************************************************** /// \param[in] row The row. //**************************************************************************************************************************************************** User *UserList::get(int row) const { if ((row < 0) || (row >= users_.count())) { app().log().error(QString("Requesting invalid user at row %1 (user count = %2)").arg(row).arg(users_.count())); return nullptr; } app().log().debug(QString("Retrieving user at row %1 (user count = %2)").arg(row).arg(users_.count())); return users_[row].get(); } //**************************************************************************************************************************************************** /// \param[in] userID The userID. //**************************************************************************************************************************************************** void UserList::onUserChanged(QString const &userID) { int const index = this->rowOfUserID(userID); SPUser user; grpc::Status status = app().grpc().getUser(userID, user); if ((!user) || (!status.ok())) { if (index >= 0) // user exists here but not in the go backend. we delete it. { app().log().debug(QString("Removing user from userlist: %1").arg(userID)); this->removeUserAt(index); } return; } if (index < 0) { app().log().debug(QString("Adding user in userlist: %1").arg(userID)); this->appendUser(user); return; } app().log().debug(QString("Updating user in userlist: %1").arg(userID)); this->updateUserAtRow(index, *user); } //**************************************************************************************************************************************************** /// The only purpose of this function is to forward the toggleSplitModeFinished event received from gRPC to the /// appropriate user. /// /// \param[in] userID the userID. //**************************************************************************************************************************************************** void UserList::onToggleSplitModeFinished(QString const &userID) { int const index = this->rowOfUserID(userID); if (index < 0) { app().log().error(QString("Received toggleSplitModeFinished event for unknown userID %1").arg(userID)); return; } users_[index]->emitToggleSplitModeFinished(); } //**************************************************************************************************************************************************** /// \return THe number of items in the list. //**************************************************************************************************************************************************** int UserList::count() const { return users_.size(); }