Permission model

Add a model for managing permissions (power levels) in rooms. This gets rid of a whole bunch of boiler plate in NeoChat and as a bonus makes it easy to add a feature to allow setting the permission level for any event.
This commit is contained in:
James Graham
2024-05-25 16:25:39 +00:00
parent 8199653ddd
commit a48151920d
10 changed files with 736 additions and 678 deletions

View File

@@ -181,6 +181,10 @@ add_library(neochat STATIC
jobs/neochatadd3pidjob.h
identityserverhelper.cpp
identityserverhelper.h
enums/powerlevel.cpp
enums/powerlevel.h
models/permissionsmodel.cpp
models/permissionsmodel.h
)
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES

107
src/enums/powerlevel.cpp Normal file
View File

@@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "powerlevel.h"
QString PowerLevel::nameForLevel(Level level)
{
switch (level) {
case PowerLevel::Member:
return i18n("Member");
case PowerLevel::Moderator:
return i18n("Moderator");
case PowerLevel::Admin:
return i18n("Admin");
case PowerLevel::Mute:
return i18n("Mute");
case PowerLevel::Custom:
return i18n("Custom");
default:
return {};
}
}
int PowerLevel::valueForLevel(Level level)
{
switch (level) {
case PowerLevel::Member:
return 0;
case PowerLevel::Moderator:
return 50;
case PowerLevel::Admin:
return 100;
case PowerLevel::Mute:
return -1;
default:
return {};
}
}
PowerLevel::Level PowerLevel::levelForValue(int value)
{
switch (value) {
case 0:
return PowerLevel::Member;
case 50:
return PowerLevel::Moderator;
case 100:
return PowerLevel::Admin;
case -1:
return PowerLevel::Mute;
default:
return PowerLevel::Custom;
}
}
PowerLevelModel::PowerLevelModel(QObject *parent)
: QAbstractListModel(parent)
{
}
bool PowerLevelModel::showMute() const
{
return m_showMute;
}
void PowerLevelModel::setShowMute(bool showMute)
{
if (showMute == m_showMute) {
return;
}
m_showMute = showMute;
Q_EMIT showMuteChanged();
}
QVariant PowerLevelModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
if (index.row() >= rowCount()) {
qDebug() << "PowerLevelModel, something's wrong: index.row() >= m_rules.count()";
return {};
}
const auto level = static_cast<PowerLevel::Level>(index.row());
if (role == NameRole) {
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
"%1 (%2)",
PowerLevel::nameForLevel(level),
PowerLevel::valueForLevel(level));
}
if (role == ValueRole) {
return PowerLevel::valueForLevel(level);
}
return {};
}
int PowerLevelModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return PowerLevel::NUMLevels - (m_showMute ? 0 : 1);
}
QHash<int, QByteArray> PowerLevelModel::roleNames() const
{
return {{NameRole, "name"}, {ValueRole, "value"}};
}

110
src/enums/powerlevel.h Normal file
View File

@@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QAbstractListModel>
#include <QObject>
#include <QQmlEngine>
#include <KLocalizedString>
/**
* @class PowerLevel
*
* This class is designed to define the PowerLevel enumeration.
*/
class PowerLevel : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
public:
/**
* @brief The type of delegate that is needed for the event.
*
* @note While similar this is not the matrix event or message type. This is
* to tell a QML ListView what delegate to show for each event. So while
* similar to the spec it is not the same.
*/
enum Level {
Member, /**< A basic member. */
Moderator, /**< A moderator with enhanced powers. */
Admin, /**< The highest power level in the room. */
Mute, /**< The level to remove posting privileges. */
NUMLevels,
Custom, /**< A non-standard value. Intentionally after NUMLevels so it doesn't appear in the model. */
};
Q_ENUM(Level);
/**
* @brief Return a string representation of the enum value.
*/
static QString nameForLevel(Level level);
/**
* @brief Return the integer representation of the enum value.
*/
static int valueForLevel(Level level);
/**
* @brief Return the enum value for the given integer power level.
*/
static Level levelForValue(int value);
};
/**
* @class PowerLevelModel
*
* A model visualize the allowed power levels.
*/
class PowerLevelModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool showMute READ showMute WRITE setShowMute NOTIFY showMuteChanged)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
NameRole = Qt::DisplayRole, /**< The power level name. */
ValueRole, /**< The power level value. */
};
Q_ENUM(Roles)
explicit PowerLevelModel(QObject *parent = nullptr);
[[nodiscard]] bool showMute() const;
void setShowMute(bool showMute);
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void showMuteChanged();
private:
bool m_showMute = true;
};

View File

@@ -0,0 +1,254 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include "permissionsmodel.h"
#include "powerlevel.h"
#include <Quotient/events/roompowerlevelsevent.h>
#include <KLazyLocalizedString>
static const QStringList defaultPermissions = {
QStringLiteral("users_default"),
QStringLiteral("state_default"),
QStringLiteral("events_default"),
QStringLiteral("invite"),
QStringLiteral("kick"),
QStringLiteral("ban"),
QStringLiteral("redact"),
QStringLiteral("m.reaction"),
QStringLiteral("m.room.redaction"),
QStringLiteral("m.room.power_levels"),
QStringLiteral("m.room.name"),
QStringLiteral("m.room.avatar"),
QStringLiteral("m.room.canonical_alias"),
QStringLiteral("m.room.topic"),
QStringLiteral("m.room.encryption"),
QStringLiteral("m.room.history_visibility"),
QStringLiteral("m.room.pinned_events"),
QStringLiteral("m.room.tombstone"),
QStringLiteral("m.room.server_acl"),
QStringLiteral("m.space.child"),
QStringLiteral("m.space.parent"),
};
// Alternate name text for default permissions.
static const QHash<QString, KLazyLocalizedString> defaultPermissionNames = {
{QStringLiteral("users_default"), kli18nc("Room permission type", "Default user power level")},
{QStringLiteral("state_default"), kli18nc("Room permission type", "Default power level to set the room state")},
{QStringLiteral("events_default"), kli18nc("Room permission type", "Default power level to send messages")},
{QStringLiteral("invite"), kli18nc("Room permission type", "Invite users")},
{QStringLiteral("kick"), kli18nc("Room permission type", "Kick users")},
{QStringLiteral("ban"), kli18nc("Room permission type", "Ban users")},
{QStringLiteral("redact"), kli18nc("Room permission type", "Remove messages sent by other users")},
{QStringLiteral("m.reaction"), kli18nc("Room permission type", "Send reactions")},
{QStringLiteral("m.room.redaction"), kli18nc("Room permission type", "Remove their own messages")},
{QStringLiteral("m.room.power_levels"), kli18nc("Room permission type", "Change user permissions")},
{QStringLiteral("m.room.name"), kli18nc("Room permission type", "Change the room name")},
{QStringLiteral("m.room.avatar"), kli18nc("Room permission type", "Change the room avatar")},
{QStringLiteral("m.room.canonical_alias"), kli18nc("Room permission type", "Change the room canonical alias")},
{QStringLiteral("m.room.topic"), kli18nc("Room permission type", "Change the room topic")},
{QStringLiteral("m.room.encryption"), kli18nc("Room permission type", "Enable encryption for the room")},
{QStringLiteral("m.room.history_visibility"), kli18nc("Room permission type", "Change the room history visibility")},
{QStringLiteral("m.room.pinned_events"), kli18nc("Room permission type", "Set pinned events")},
{QStringLiteral("m.room.tombstone"), kli18nc("Room permission type", "Upgrade the room")},
{QStringLiteral("m.room.server_acl"), kli18nc("Room permission type", "Set the room server access control list (ACL)")},
{QStringLiteral("m.space.child"), kli18nc("Room permission type", "Set the children of this space")},
{QStringLiteral("m.space.parent"), kli18nc("Room permission type", "Set the parent space of this room")},
};
// Subtitles for the default values.
static const QHash<QString, KLazyLocalizedString> defaultSubtitles = {
{QStringLiteral("users_default"), kli18nc("Room permission type", "This is the power level for all new users when joining the room")},
{QStringLiteral("state_default"), kli18nc("Room permission type", "This is used for all state events that do not have their own entry here")},
{QStringLiteral("events_default"), kli18nc("Room permission type", "This is used for all message events that do not have their own entry here")},
};
// Permissions that should use the event default.
static const QStringList eventPermissions = {
QStringLiteral("m.room.message"),
QStringLiteral("m.reaction"),
QStringLiteral("m.room.redaction"),
};
PermissionsModel::PermissionsModel(QObject *parent)
: QAbstractListModel(parent)
{
}
NeoChatRoom *PermissionsModel::room() const
{
return m_room;
}
void PermissionsModel::setRoom(NeoChatRoom *room)
{
if (room == m_room) {
return;
}
m_room = room;
Q_EMIT roomChanged();
initializeModel();
}
void PermissionsModel::initializeModel()
{
beginResetModel();
m_permissions.clear();
if (m_room == nullptr) {
endResetModel();
return;
}
const auto currentPowerLevelEvent = m_room->currentState().get<Quotient::RoomPowerLevelsEvent>();
if (currentPowerLevelEvent == nullptr) {
return;
}
m_permissions.append(defaultPermissions);
for (const auto &event : currentPowerLevelEvent->events().keys()) {
if (!m_permissions.contains(event)) {
m_permissions += event;
}
}
endResetModel();
}
QVariant PermissionsModel::data(const QModelIndex &index, int role) const
{
if (m_room == nullptr || !index.isValid()) {
return {};
}
if (index.row() >= rowCount()) {
qDebug() << "PushRuleModel, something's wrong: index.row() >= m_rules.count()";
return {};
}
const auto permission = m_permissions.value(index.row());
if (role == NameRole) {
if (defaultPermissionNames.keys().contains(permission)) {
return defaultPermissionNames.value(permission).toString();
}
return permission;
}
if (role == SubtitleRole) {
if (permission.startsWith(QLatin1String("m.")) && defaultPermissionNames.keys().contains(permission)) {
return permission;
}
if (defaultSubtitles.contains(permission)) {
return defaultSubtitles.value(permission).toString();
}
return QString();
}
if (role == TypeRole) {
return permission;
}
if (role == LevelRole) {
const auto level = powerLevel(permission);
if (level.has_value()) {
return *level;
}
return {};
}
if (role == LevelNameRole) {
const auto level = powerLevel(permission);
if (level.has_value()) {
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
"%1 (%2)",
PowerLevel::nameForLevel(PowerLevel::levelForValue(*level)),
*level);
}
return QString();
}
if (role == IsDefaultValueRole) {
return permission.contains(QLatin1String("default"));
}
if (role == IsBasicPermissionRole) {
return permission == QStringLiteral("invite") || permission == QStringLiteral("kick") || permission == QStringLiteral("ban")
|| permission == QStringLiteral("redact");
}
return {};
}
int PermissionsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_permissions.count();
}
QHash<int, QByteArray> PermissionsModel::roleNames() const
{
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
roles[NameRole] = "name";
roles[SubtitleRole] = "subtitle";
roles[TypeRole] = "type";
roles[LevelRole] = "level";
roles[LevelNameRole] = "levelName";
roles[IsDefaultValueRole] = "isDefaultValue";
roles[IsBasicPermissionRole] = "isBasicPermission";
return roles;
}
std::optional<int> PermissionsModel::powerLevel(const QString &permission) const
{
if (m_room == nullptr) {
return std::nullopt;
}
if (const auto currentPowerLevelEvent = m_room->currentState().get<Quotient::RoomPowerLevelsEvent>()) {
if (permission == QStringLiteral("ban")) {
return currentPowerLevelEvent->ban();
} else if (permission == QStringLiteral("kick")) {
return currentPowerLevelEvent->kick();
} else if (permission == QStringLiteral("invite")) {
return currentPowerLevelEvent->invite();
} else if (permission == QStringLiteral("redact")) {
return currentPowerLevelEvent->redact();
} else if (permission == QStringLiteral("users_default")) {
return currentPowerLevelEvent->usersDefault();
} else if (permission == QStringLiteral("state_default")) {
return currentPowerLevelEvent->stateDefault();
} else if (permission == QStringLiteral("events_default")) {
return currentPowerLevelEvent->eventsDefault();
} else if (eventPermissions.contains(permission)) {
return currentPowerLevelEvent->powerLevelForEvent(permission);
} else {
return currentPowerLevelEvent->powerLevelForState(permission);
}
}
return std::nullopt;
}
void PermissionsModel::setPowerLevel(const QString &permission, const int &newPowerLevel)
{
if (m_room == nullptr) {
return;
}
int clampPowerLevel = std::clamp(newPowerLevel, -1, 100);
const auto currentPowerLevel = powerLevel(permission);
if (!currentPowerLevel.has_value() || currentPowerLevel == clampPowerLevel) {
return;
}
if (auto currentPowerLevelEvent = m_room->currentState().get<Quotient::RoomPowerLevelsEvent>()) {
auto powerLevelContent = currentPowerLevelEvent->contentJson();
if (powerLevelContent.contains(permission)) {
powerLevelContent[permission] = clampPowerLevel;
} else {
auto eventPowerLevels = powerLevelContent[QLatin1String("events")].toObject();
eventPowerLevels[permission] = clampPowerLevel;
powerLevelContent[QLatin1String("events")] = eventPowerLevels;
}
m_room->setState<Quotient::RoomPowerLevelsEvent>(powerLevelContent);
}
}
#include "moc_permissionsmodel.cpp"

View File

@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <QAbstractListModel>
#include <QQmlEngine>
#include <optional>
#include "neochatroom.h"
/**
* @class PermissionsModel
*
* This class defines the model for managing room permission levels.
*/
class PermissionsModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
/**
* @brief The room to show the permissions for
*/
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
public:
/**
* @brief Defines the model roles.
*/
enum Roles {
NameRole = Qt::DisplayRole, /**< The permission name. */
SubtitleRole, /**< The description of the permission. */
TypeRole, /**< The base type of the permission, normally the event type id except for ban, kick, etc. */
LevelRole, /**< The current power level for the permission. */
LevelNameRole, /**< The current power level for the permission as a string. */
IsDefaultValueRole, /**< Whether the permission is a default value, e.g. for users. */
IsBasicPermissionRole, /**< Whether the permission is one of the basic ones, e.g. kick, ban, etc. */
};
Q_ENUM(Roles)
explicit PermissionsModel(QObject *parent = nullptr);
NeoChatRoom *room() const;
void setRoom(NeoChatRoom *room);
/**
* @brief Get the given role value at the given index.
*
* @sa QAbstractItemModel::data
*/
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
/**
* @brief Number of rows in the model.
*
* @sa QAbstractItemModel::rowCount
*/
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
/**
* @brief Returns a mapping from Role enum values to role names.
*
* @sa Roles, QAbstractItemModel::roleNames()
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
/**
* @brief Return the power level required for the given permission.
*/
std::optional<int> powerLevel(const QString &permission) const;
/**
* @brief Set the power level required for the given permission.
*/
Q_INVOKABLE void setPowerLevel(const QString &permission, const int &newPowerLevel);
Q_SIGNALS:
void roomChanged();
private:
QPointer<NeoChatRoom> m_room;
QStringList m_permissions;
void initializeModel();
};

View File

@@ -7,6 +7,7 @@
#include <Quotient/events/roompowerlevelsevent.h>
#include "enums/powerlevel.h"
#include "neochatroom.h"
using namespace Quotient;
@@ -94,16 +95,10 @@ QVariant UserListModel::data(const QModelIndex &index, int role) const
auto userPl = pl->powerLevelForUser(user->id());
switch (userPl) {
case 0:
return QStringLiteral("Member");
case 50:
return QStringLiteral("Moderator");
case 100:
return QStringLiteral("Admin");
default:
return QStringLiteral("Custom");
}
return i18nc("%1 is the name of the power level, e.g. admin and %2 is the value that represents.",
"%1 (%2)",
PowerLevel::nameForLevel(PowerLevel::levelForValue(userPl)),
userPl);
}
return {};

View File

@@ -876,7 +876,7 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel
qWarning() << "User is not a member of this room so power level cannot be set";
return;
}
int clampPowerLevel = std::clamp(powerLevel, 0, 100);
int clampPowerLevel = std::clamp(powerLevel, -1, 100);
auto powerLevelContent = currentState().get("m.room.power_levels"_ls)->contentJson();
auto powerLevelUserOverrides = powerLevelContent["users"_ls].toObject();
@@ -898,254 +898,6 @@ int NeoChatRoom::getUserPowerLevel(const QString &userId) const
return powerLevelEvent->powerLevelForUser(userId);
}
int NeoChatRoom::powerLevel(const QString &eventName, const bool &isStateEvent) const
{
const auto powerLevelEvent = currentState().get<RoomPowerLevelsEvent>();
if (eventName == "ban"_ls) {
return powerLevelEvent->ban();
} else if (eventName == "kick"_ls) {
return powerLevelEvent->kick();
} else if (eventName == "invite"_ls) {
return powerLevelEvent->invite();
} else if (eventName == "redact"_ls) {
return powerLevelEvent->redact();
} else if (eventName == "users_default"_ls) {
return powerLevelEvent->usersDefault();
} else if (eventName == "state_default"_ls) {
return powerLevelEvent->stateDefault();
} else if (eventName == "events_default"_ls) {
return powerLevelEvent->eventsDefault();
} else if (isStateEvent) {
return powerLevelEvent->powerLevelForState(eventName);
} else {
return powerLevelEvent->powerLevelForEvent(eventName);
}
}
void NeoChatRoom::setPowerLevel(const QString &eventName, const int &newPowerLevel, const bool &isStateEvent)
{
auto powerLevelContent = currentState().get("m.room.power_levels"_ls)->contentJson();
int clampPowerLevel = std::clamp(newPowerLevel, 0, 100);
int powerLevel = 0;
if (powerLevelContent.contains(eventName)) {
powerLevel = powerLevelContent[eventName].toInt();
if (powerLevel != clampPowerLevel) {
powerLevelContent[eventName] = clampPowerLevel;
}
} else {
auto eventPowerLevels = powerLevelContent["events"_ls].toObject();
if (eventPowerLevels.contains(eventName)) {
powerLevel = eventPowerLevels[eventName].toInt();
} else {
if (isStateEvent) {
powerLevel = powerLevelContent["state_default"_ls].toInt();
} else {
powerLevel = powerLevelContent["events_default"_ls].toInt();
}
}
if (powerLevel != clampPowerLevel) {
eventPowerLevels[eventName] = clampPowerLevel;
powerLevelContent["events"_ls] = eventPowerLevels;
}
}
setState("m.room.power_levels"_ls, {}, powerLevelContent);
}
int NeoChatRoom::defaultUserPowerLevel() const
{
return powerLevel("users_default"_ls);
}
void NeoChatRoom::setDefaultUserPowerLevel(const int &newPowerLevel)
{
setPowerLevel("users_default"_ls, newPowerLevel);
}
int NeoChatRoom::invitePowerLevel() const
{
return powerLevel("invite"_ls);
}
void NeoChatRoom::setInvitePowerLevel(const int &newPowerLevel)
{
setPowerLevel("invite"_ls, newPowerLevel);
}
int NeoChatRoom::kickPowerLevel() const
{
return powerLevel("kick"_ls);
}
void NeoChatRoom::setKickPowerLevel(const int &newPowerLevel)
{
setPowerLevel("kick"_ls, newPowerLevel);
}
int NeoChatRoom::banPowerLevel() const
{
return powerLevel("ban"_ls);
}
void NeoChatRoom::setBanPowerLevel(const int &newPowerLevel)
{
setPowerLevel("ban"_ls, newPowerLevel);
}
int NeoChatRoom::redactPowerLevel() const
{
return powerLevel("redact"_ls);
}
void NeoChatRoom::setRedactPowerLevel(const int &newPowerLevel)
{
setPowerLevel("redact"_ls, newPowerLevel);
}
int NeoChatRoom::statePowerLevel() const
{
return powerLevel("state_default"_ls);
}
void NeoChatRoom::setStatePowerLevel(const int &newPowerLevel)
{
setPowerLevel("state_default"_ls, newPowerLevel);
}
int NeoChatRoom::defaultEventPowerLevel() const
{
return powerLevel("events_default"_ls);
}
void NeoChatRoom::setDefaultEventPowerLevel(const int &newPowerLevel)
{
setPowerLevel("events_default"_ls, newPowerLevel);
}
int NeoChatRoom::powerLevelPowerLevel() const
{
return powerLevel("m.room.power_levels"_ls, true);
}
void NeoChatRoom::setPowerLevelPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.power_levels"_ls, newPowerLevel, true);
}
int NeoChatRoom::namePowerLevel() const
{
return powerLevel("m.room.name"_ls, true);
}
void NeoChatRoom::setNamePowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.name"_ls, newPowerLevel, true);
}
int NeoChatRoom::avatarPowerLevel() const
{
return powerLevel("m.room.avatar"_ls, true);
}
void NeoChatRoom::setAvatarPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.avatar"_ls, newPowerLevel, true);
}
int NeoChatRoom::canonicalAliasPowerLevel() const
{
return powerLevel("m.room.canonical_alias"_ls, true);
}
void NeoChatRoom::setCanonicalAliasPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.canonical_alias"_ls, newPowerLevel, true);
}
int NeoChatRoom::topicPowerLevel() const
{
return powerLevel("m.room.topic"_ls, true);
}
void NeoChatRoom::setTopicPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.topic"_ls, newPowerLevel, true);
}
int NeoChatRoom::encryptionPowerLevel() const
{
return powerLevel("m.room.encryption"_ls, true);
}
void NeoChatRoom::setEncryptionPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.encryption"_ls, newPowerLevel, true);
}
int NeoChatRoom::historyVisibilityPowerLevel() const
{
return powerLevel("m.room.history_visibility"_ls, true);
}
void NeoChatRoom::setHistoryVisibilityPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.history_visibility"_ls, newPowerLevel, true);
}
int NeoChatRoom::pinnedEventsPowerLevel() const
{
return powerLevel("m.room.pinned_events"_ls, true);
}
void NeoChatRoom::setPinnedEventsPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.pinned_events"_ls, newPowerLevel, true);
}
int NeoChatRoom::tombstonePowerLevel() const
{
return powerLevel("m.room.tombstone"_ls, true);
}
void NeoChatRoom::setTombstonePowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.tombstone"_ls, newPowerLevel, true);
}
int NeoChatRoom::serverAclPowerLevel() const
{
return powerLevel("m.room.server_acl"_ls, true);
}
void NeoChatRoom::setServerAclPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.room.server_acl"_ls, newPowerLevel, true);
}
int NeoChatRoom::spaceChildPowerLevel() const
{
return powerLevel("m.space.child"_ls, true);
}
void NeoChatRoom::setSpaceChildPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.space.child"_ls, newPowerLevel, true);
}
int NeoChatRoom::spaceParentPowerLevel() const
{
return powerLevel("m.space.parent"_ls, true);
}
void NeoChatRoom::setSpaceParentPowerLevel(const int &newPowerLevel)
{
setPowerLevel("m.space.parent"_ls, newPowerLevel, true);
}
QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QString reason)
{
QStringList events;

View File

@@ -212,101 +212,6 @@ class NeoChatRoom : public Quotient::Room
*/
Q_PROPERTY(bool canEncryptRoom READ canEncryptRoom NOTIFY canEncryptRoomChanged)
/**
* @brief The default power level in the room for new users.
*/
Q_PROPERTY(int defaultUserPowerLevel READ defaultUserPowerLevel WRITE setDefaultUserPowerLevel NOTIFY defaultUserPowerLevelChanged)
/**
* @brief The power level required to invite users to the room.
*/
Q_PROPERTY(int invitePowerLevel READ invitePowerLevel WRITE setInvitePowerLevel NOTIFY invitePowerLevelChanged)
/**
* @brief The power level required to kick users from the room.
*/
Q_PROPERTY(int kickPowerLevel READ kickPowerLevel WRITE setKickPowerLevel NOTIFY kickPowerLevelChanged)
/**
* @brief The power level required to ban users from the room.
*/
Q_PROPERTY(int banPowerLevel READ banPowerLevel WRITE setBanPowerLevel NOTIFY banPowerLevelChanged)
/**
* @brief The power level required to delete other user messages.
*/
Q_PROPERTY(int redactPowerLevel READ redactPowerLevel WRITE setRedactPowerLevel NOTIFY redactPowerLevelChanged)
/**
* @brief The default power level for state events that are not explicitly specified.
*/
Q_PROPERTY(int statePowerLevel READ statePowerLevel WRITE setStatePowerLevel NOTIFY statePowerLevelChanged)
/**
* @brief The default power level for event that are not explicitly specified.
*/
Q_PROPERTY(int defaultEventPowerLevel READ defaultEventPowerLevel WRITE setDefaultEventPowerLevel NOTIFY defaultEventPowerLevelChanged)
/**
* @brief The power level required to change power levels for the room.
*/
Q_PROPERTY(int powerLevelPowerLevel READ powerLevelPowerLevel WRITE setPowerLevelPowerLevel NOTIFY powerLevelPowerLevelChanged)
/**
* @brief The power level required to change the room name.
*/
Q_PROPERTY(int namePowerLevel READ namePowerLevel WRITE setNamePowerLevel NOTIFY namePowerLevelChanged)
/**
* @brief The power level required to change the room avatar.
*/
Q_PROPERTY(int avatarPowerLevel READ avatarPowerLevel WRITE setAvatarPowerLevel NOTIFY avatarPowerLevelChanged)
/**
* @brief The power level required to change the room aliases.
*/
Q_PROPERTY(int canonicalAliasPowerLevel READ canonicalAliasPowerLevel WRITE setCanonicalAliasPowerLevel NOTIFY canonicalAliasPowerLevelChanged)
/**
* @brief The power level required to change the room topic.
*/
Q_PROPERTY(int topicPowerLevel READ topicPowerLevel WRITE setTopicPowerLevel NOTIFY topicPowerLevelChanged)
/**
* @brief The power level required to encrypt the room.
*/
Q_PROPERTY(int encryptionPowerLevel READ encryptionPowerLevel WRITE setEncryptionPowerLevel NOTIFY encryptionPowerLevelChanged)
/**
* @brief The power level required to change the room history visibility.
*/
Q_PROPERTY(int historyVisibilityPowerLevel READ historyVisibilityPowerLevel WRITE setHistoryVisibilityPowerLevel NOTIFY historyVisibilityPowerLevelChanged)
/**
* @brief The power level required to pin events in the room.
*/
Q_PROPERTY(int pinnedEventsPowerLevel READ pinnedEventsPowerLevel WRITE setPinnedEventsPowerLevel NOTIFY pinnedEventsPowerLevelChanged)
/**
* @brief The power level required to upgrade the room.
*/
Q_PROPERTY(int tombstonePowerLevel READ tombstonePowerLevel WRITE setTombstonePowerLevel NOTIFY tombstonePowerLevelChanged)
/**
* @brief The power level required to set the room server access control list (ACL).
*/
Q_PROPERTY(int serverAclPowerLevel READ serverAclPowerLevel WRITE setServerAclPowerLevel NOTIFY serverAclPowerLevelChanged)
/**
* @brief The power level required to add children to a space.
*/
Q_PROPERTY(int spaceChildPowerLevel READ spaceChildPowerLevel WRITE setSpaceChildPowerLevel NOTIFY spaceChildPowerLevelChanged)
/**
* @brief The power level required to set the room parent space.
*/
Q_PROPERTY(int spaceParentPowerLevel READ spaceParentPowerLevel WRITE setSpaceParentPowerLevel NOTIFY spaceParentPowerLevelChanged)
/**
* @brief The cache for the main chat bar in the room.
*/
@@ -683,66 +588,6 @@ public:
Q_INVOKABLE void setUserPowerLevel(const QString &userID, const int &powerLevel);
[[nodiscard]] int powerLevel(const QString &eventName, const bool &isStateEvent = false) const;
void setPowerLevel(const QString &eventName, const int &newPowerLevel, const bool &isStateEvent = false);
[[nodiscard]] int defaultUserPowerLevel() const;
void setDefaultUserPowerLevel(const int &newPowerLevel);
[[nodiscard]] int invitePowerLevel() const;
void setInvitePowerLevel(const int &newPowerLevel);
[[nodiscard]] int kickPowerLevel() const;
void setKickPowerLevel(const int &newPowerLevel);
[[nodiscard]] int banPowerLevel() const;
void setBanPowerLevel(const int &newPowerLevel);
[[nodiscard]] int redactPowerLevel() const;
void setRedactPowerLevel(const int &newPowerLevel);
[[nodiscard]] int statePowerLevel() const;
void setStatePowerLevel(const int &newPowerLevel);
[[nodiscard]] int defaultEventPowerLevel() const;
void setDefaultEventPowerLevel(const int &newPowerLevel);
[[nodiscard]] int powerLevelPowerLevel() const;
void setPowerLevelPowerLevel(const int &newPowerLevel);
[[nodiscard]] int namePowerLevel() const;
void setNamePowerLevel(const int &newPowerLevel);
[[nodiscard]] int avatarPowerLevel() const;
void setAvatarPowerLevel(const int &newPowerLevel);
[[nodiscard]] int canonicalAliasPowerLevel() const;
void setCanonicalAliasPowerLevel(const int &newPowerLevel);
[[nodiscard]] int topicPowerLevel() const;
void setTopicPowerLevel(const int &newPowerLevel);
[[nodiscard]] int encryptionPowerLevel() const;
void setEncryptionPowerLevel(const int &newPowerLevel);
[[nodiscard]] int historyVisibilityPowerLevel() const;
void setHistoryVisibilityPowerLevel(const int &newPowerLevel);
[[nodiscard]] int pinnedEventsPowerLevel() const;
void setPinnedEventsPowerLevel(const int &newPowerLevel);
[[nodiscard]] int tombstonePowerLevel() const;
void setTombstonePowerLevel(const int &newPowerLevel);
[[nodiscard]] int serverAclPowerLevel() const;
void setServerAclPowerLevel(const int &newPowerLevel);
[[nodiscard]] int spaceChildPowerLevel() const;
void setSpaceChildPowerLevel(const int &newPowerLevel);
[[nodiscard]] int spaceParentPowerLevel() const;
void setSpaceParentPowerLevel(const int &newPowerLevel);
ChatBarCache *mainCache() const;
ChatBarCache *editCache() const;
@@ -858,25 +703,6 @@ Q_SIGNALS:
void defaultUrlPreviewStateChanged();
void urlPreviewEnabledChanged();
void maxRoomVersionChanged();
void defaultUserPowerLevelChanged();
void invitePowerLevelChanged();
void kickPowerLevelChanged();
void banPowerLevelChanged();
void redactPowerLevelChanged();
void statePowerLevelChanged();
void defaultEventPowerLevelChanged();
void powerLevelPowerLevelChanged();
void namePowerLevelChanged();
void avatarPowerLevelChanged();
void canonicalAliasPowerLevelChanged();
void topicPowerLevelChanged();
void encryptionPowerLevelChanged();
void historyVisibilityPowerLevelChanged();
void pinnedEventsPowerLevelChanged();
void tombstonePowerLevelChanged();
void serverAclPowerLevelChanged();
void spaceChildPowerLevelChanged();
void spaceParentPowerLevelChanged();
void replyLoaded(const QString &eventId, const QString &replyId);
public Q_SLOTS:

View File

@@ -28,32 +28,14 @@ Kirigami.Dialog {
}
}
FormCard.FormCard {
ColumnLayout {
FormCard.FormComboBoxDelegate {
id: powerLevelComboBox
text: i18n("New power level")
model: ListModel {
id: powerLevelModel
}
textRole: "text"
valueRole: "powerLevel"
// Done this way so we can have translated strings.
Component.onCompleted: {
powerLevelModel.append({
"text": i18n("Member (0)"),
"powerLevel": 0
});
powerLevelModel.append({
"text": i18n("Moderator (50)"),
"powerLevel": 50
});
powerLevelModel.append({
"text": i18n("Admin (100)"),
"powerLevel": 100
});
}
model: PowerLevelModel {}
textRole: "name"
valueRole: "value"
}
}
customFooterActions: [

View File

@@ -25,8 +25,12 @@ FormCard.FormCardPage {
room: root.room
}
property ListModel powerLevelModel: ListModel {
id: powerLevelModel
readonly property PowerLevelModel powerLevelModel: PowerLevelModel {
showMute: false
}
readonly property PermissionsModel permissionsModel: PermissionsModel {
room: root.room
}
FormCard.FormHeader {
@@ -40,10 +44,16 @@ FormCard.FormCardPage {
sortOrder: Qt.DescendingOrder
filterRowCallback: function (source_row, source_parent) {
let powerLevelRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), UserListModel.PowerLevelRole);
return powerLevelRole > 0;
return powerLevelRole != 0;
}
}
delegate: FormCard.FormTextDelegate {
id: privilegedUserDelegate
required property string userId
required property string name
required property int powerLevel
required property string powerLevelString
text: name
textItem.textFormat: Text.PlainText
description: userId
@@ -51,37 +61,23 @@ FormCard.FormCardPage {
spacing: Kirigami.Units.largeSpacing
QQC2.Label {
id: powerLevelLabel
visible: !room.canSendState("m.room.power_levels") || (room.getUserPowerLevel(room.localUser.id) <= model.powerLevel && model.userId != room.localUser.id)
text: powerLevelString
visible: !room.canSendState("m.room.power_levels") || (room.getUserPowerLevel(room.localUser.id) <= privilegedUserDelegate.powerLevel && privilegedUserDelegate.userId != room.localUser.id)
text: privilegedUserDelegate.powerLevelString
color: Kirigami.Theme.disabledTextColor
}
QQC2.ComboBox {
focusPolicy: Qt.NoFocus // provided by parent
model: powerLevelModel
textRole: "text"
valueRole: "powerLevel"
model: PowerLevelModel {}
textRole: "name"
valueRole: "value"
visible: !powerLevelLabel.visible
Component.onCompleted: {
/**
* This is very silly but the only way to populate the model with
* translated strings. Done here because the model needs to be filled
* before the first delegate sets it's current index.
*/
if (powerLevelModel.count == 0) {
powerLevelModel.append({
"text": i18n("Member (0)"),
"powerLevel": 0
});
powerLevelModel.append({
"text": i18n("Moderator (50)"),
"powerLevel": 50
});
powerLevelModel.append({
"text": i18n("Admin (100)"),
"powerLevel": 100
});
let index = indexOfValue(privilegedUserDelegate.powerLevel)
if (index === -1) {
displayText = privilegedUserDelegate.powerLevelString;
} else {
currentIndex = index;
}
currentIndex = indexOfValue(powerLevel);
}
onActivated: {
room.setUserPowerLevel(userId, currentValue);
@@ -243,37 +239,36 @@ FormCard.FormCardPage {
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Default user power level")
description: i18n("This is power level for all new users when joining the room")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultUserPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.defaultUserPowerLevel = currentValue;
Repeater {
model: KSortFilterProxyModel {
sourceModel: root.permissionsModel
filterRowCallback: function (source_row, source_parent) {
return sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsDefaultValueRole);
}
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Default power level to set the room state")
description: i18n("This is used for all state events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.statePowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.statePowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Default power level to send messages")
description: i18n("This is used for all message events that do not have their own entry here")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.defaultEventPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.defaultEventPowerLevel = currentValue;
delegate: FormCard.FormComboBoxDelegate {
required property string name
required property string subtitle
required property string type
required property int level
required property string levelName
text: name
description: subtitle
textRole: "name"
valueRole: "value"
model: root.powerLevelModel
Component.onCompleted: {
let index = indexOfValue(level)
if (index === -1) {
displayText = levelName;
} else {
currentIndex = index;
}
}
onCurrentValueChanged: if (root.room.canSendState("m.room.power_levels")) {
root.permissionsModel.setPowerLevel(type, currentValue);
}
}
}
}
@@ -284,44 +279,36 @@ FormCard.FormCardPage {
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Invite users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.invitePowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.invitePowerLevel = currentValue;
Repeater {
model: KSortFilterProxyModel {
sourceModel: root.permissionsModel
filterRowCallback: function (source_row, source_parent) {
return sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsBasicPermissionRole);
}
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Kick users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.kickPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.kickPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Ban users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.banPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.banPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Remove message sent by other users")
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.redactPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.redactPowerLevel = currentValue;
delegate: FormCard.FormComboBoxDelegate {
required property string name
required property string subtitle
required property string type
required property int level
required property string levelName
text: name
description: subtitle
textRole: "name"
valueRole: "value"
model: root.powerLevelModel
Component.onCompleted: {
let index = indexOfValue(level)
if (index === -1) {
displayText = levelName;
} else {
currentIndex = index;
}
}
onCurrentValueChanged: if (root.room.canSendState("m.room.power_levels")) {
root.permissionsModel.setPowerLevel(type, currentValue);
}
}
}
}
@@ -332,137 +319,91 @@ FormCard.FormCardPage {
}
FormCard.FormCard {
visible: room.canSendState("m.room.power_levels")
FormCard.FormComboBoxDelegate {
text: i18n("Change user permissions")
description: "m.room.power_levels"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.powerLevelPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.powerLevelPowerLevel = currentValue;
Repeater {
model: KSortFilterProxyModel {
sourceModel: root.permissionsModel
filterRowCallback: function (source_row, source_parent) {
let isBasicPermissionRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsBasicPermissionRole);
let isDefaultValueRole = sourceModel.data(sourceModel.index(source_row, 0, source_parent), PermissionsModel.IsDefaultValueRole);
return !isBasicPermissionRole && !isDefaultValueRole;
}
}
delegate: FormCard.FormComboBoxDelegate {
required property string name
required property string subtitle
required property string type
required property int level
required property string levelName
text: name
description: subtitle
textRole: "name"
valueRole: "value"
model: root.powerLevelModel
Component.onCompleted: {
let index = indexOfValue(level)
if (index === -1) {
displayText = levelName;
} else {
currentIndex = index;
}
}
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
root.permissionsModel.setPowerLevel(type, currentValue);
}
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room name")
description: "m.room.name"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.namePowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.namePowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room avatar")
description: "m.room.avatar"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.avatarPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.avatarPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room canonical alias")
description: "m.room.canonical_alias"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.canonicalAliasPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.canonicalAliasPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room topic")
description: "m.room.topic"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.topicPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.topicPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Enable encryption for the room")
description: "m.room.encryption"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.encryptionPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.encryptionPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Change the room history visibility")
description: "m.room.history_visibility"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.historyVisibilityPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.historyVisibilityPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Set pinned events")
description: "m.room.pinned_events"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.pinnedEventsPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.pinnedEventsPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Upgrade the room")
description: "m.room.tombstone"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.tombstonePowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.tombstonePowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Set the room server access control list (ACL)")
description: "m.room.server_acl"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.serverAclPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.serverAclPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
visible: room.isSpace
text: i18n("Set the children of this space")
description: "m.space.child"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.spaceChildPowerLevel = currentValue;
}
}
FormCard.FormComboBoxDelegate {
text: i18n("Set the parent space of this room")
description: "m.space.parent"
textRole: "text"
valueRole: "powerLevel"
model: powerLevelModel
Component.onCompleted: currentIndex = indexOfValue(room.spaceChildPowerLevel)
onCurrentValueChanged: if (room.canSendState("m.room.power_levels")) {
room.spaceParentPowerLevel = currentValue;
FormCard.AbstractFormDelegate {
Layout.fillWidth: true
contentItem: RowLayout {
Kirigami.ActionTextField {
id: newEventAddField
Layout.fillWidth: true
placeholderText: i18n("Event Type…")
enabled: NotificationsManager.keywordNotificationAction !== PushRuleAction.Unknown
rightActions: Kirigami.Action {
icon.name: "edit-clear"
visible: newEventAddField.text.length > 0
onTriggered: {
newEventAddField.text = "";
}
}
onAccepted: {
root.permissionsModel.setPowerLevel(newEventAddField.text, newEventPowerLevel.currentValue);
newEventAddField.text = "";
}
}
QQC2.ComboBox {
id: newEventPowerLevel
focusPolicy: Qt.NoFocus // provided by parent
model: root.powerLevelModel
textRole: "name"
valueRole: "value"
}
QQC2.Button {
id: addButton
text: i18n("Add keyword")
Accessible.name: text
icon.name: "list-add"
display: QQC2.AbstractButton.IconOnly
enabled: newEventAddField.text.length > 0
onClicked: {
root.permissionsModel.setPowerLevel(newEventAddField.text, newEventPowerLevel.currentValue);
newEventAddField.text = "";
}
QQC2.ToolTip {
text: addButton.text
delay: Kirigami.Units.toolTipDelay
}
}
}
}
}