diff --git a/resources/qml/dialogs/PowerLevelEditor.qml b/resources/qml/dialogs/PowerLevelEditor.qml
index 241585f9..d757f0af 100644
--- a/resources/qml/dialogs/PowerLevelEditor.qml
+++ b/resources/qml/dialogs/PowerLevelEditor.qml
@@ -20,13 +20,14 @@ ApplicationWindow {
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
minimumWidth: 300
minimumHeight: 400
+ height: 600
title: qsTr("Permissions in %1").arg(roomSettings.roomName);
-// Shortcut {
-// sequence: StandardKey.Cancel
-// onActivated: dbb.rejected()
-// }
+ // Shortcut {
+ // sequence: StandardKey.Cancel
+ // onActivated: dbb.rejected()
+ // }
ColumnLayout {
anchors.margins: Nheko.paddingMedium
@@ -117,6 +118,8 @@ ApplicationWindow {
return qsTr("Administrator (%1)").arg(model.powerlevel)
else if (editingModel.moderatorLevel == model.powerlevel)
return qsTr("Moderator (%1)").arg(model.powerlevel)
+ else if (editingModel.defaultUserLevel == model.powerlevel)
+ return qsTr("User (%1)").arg(model.powerlevel)
else
return qsTr("Custom (%1)").arg(model.powerlevel)
}
@@ -144,34 +147,85 @@ ApplicationWindow {
}
}
}
- MatrixTextField {
- id: typeEntry
+ MatrixTextField {
+ id: typeEntry
- property int index
+ property int index
- width: parent.width
- z: 5
- visible: false
+ width: parent.width
+ z: 5
+ visible: false
- color: Nheko.colors.text
+ color: Nheko.colors.text
- Keys.onPressed: {
- if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) {
- editingModel.types.add(typeEntry.index, typeEntry.text)
- typeEntry.visible = false;
- typeEntry.clear();
- event.accepted = true;
+ Keys.onPressed: {
+ if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) {
+ editingModel.types.add(typeEntry.index, typeEntry.text)
+ typeEntry.visible = false;
+ typeEntry.clear();
+ event.accepted = true;
+ }
+ else if (event.matches(StandardKey.Cancel)) {
+ typeEntry.visible = false;
+ typeEntry.clear();
+ event.accepted = true;
+ }
+ }
+ }
+ }
+
+ Button {
+ Layout.fillWidth: true
+ text: qsTr("Add new role")
+
+ onClicked: newPLLay.visible = true
+
+ Rectangle {
+ id: newPLLay
+
+ anchors.fill: parent
+ visible: false
+ color: Nheko.colors.alternateBase
+
+ RowLayout {
+ spacing: Nheko.paddingMedium
+ anchors.fill: parent
+
+ SpinBox {
+ id: newPLVal
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ editable: true
+ //from: -9007199254740991
+ //to: 9007199254740991
+
+ // max qml values
+ from: -2000000000
+ to: 2000000000
+
+ Keys.onPressed: {
+ if (event.matches(StandardKey.InsertParagraphSeparator)) {
+ editingModel.addRole(newPLVal.value);
+ newPLLay.visible = false;
+ }
}
- else if (event.matches(StandardKey.Cancel)) {
- typeEntry.visible = false;
- typeEntry.clear();
- event.accepted = true;
+ }
+
+ Button {
+ text: qsTr("Add")
+ Layout.preferredWidth: 100
+ onClicked: {
+ editingModel.addRole(newPLVal.value);
+ newPLLay.visible = false;
}
}
}
+ }
}
-
}
+
ColumnLayout {
spacing: Nheko.paddingMedium
@@ -188,16 +242,16 @@ ApplicationWindow {
model: editingModel.users
- Column{
- id: userEntryCompleter
+ Column{
+ id: userEntryCompleter
- property int index: 0
+ property int index: 0
- visible: false
+ visible: false
- width: parent.width
- spacing: 1
- z: 5
+ width: parent.width
+ spacing: 1
+ z: 5
MatrixTextField {
id: userEntry
@@ -229,119 +283,119 @@ ApplicationWindow {
}
- Completer {
- id: userCompleter
+ Completer {
+ id: userCompleter
- visible: userEntry.text.length > 0
- width: parent.width
- roomId: plEditorW.roomSettings.roomId
- completerName: "user"
- bottomToTop: false
- fullWidth: true
- avatarHeight: Nheko.avatarSize / 2
- avatarWidth: Nheko.avatarSize / 2
- centerRowContent: false
- rowMargin: 2
- rowSpacing: 2
- }
+ visible: userEntry.text.length > 0
+ width: parent.width
+ roomId: plEditorW.roomSettings.roomId
+ completerName: "user"
+ bottomToTop: false
+ fullWidth: true
+ avatarHeight: Nheko.avatarSize / 2
+ avatarWidth: Nheko.avatarSize / 2
+ centerRowContent: false
+ rowMargin: 2
+ rowSpacing: 2
}
+ }
- Connections {
- function onCompletionSelected(id) {
- console.log("selected: " + id);
- editingModel.users.add(userEntryCompleter.index, id);
- userEntry.clear();
- userEntryCompleter.visible = false;
- }
-
- function onCountChanged() {
- if (userCompleter.count > 0 && (userCompleter.currentIndex < 0 || userCompleter.currentIndex >= userCompleter.count))
- userCompleter.currentIndex = 0;
+ Connections {
+ function onCompletionSelected(id) {
+ console.log("selected: " + id);
+ editingModel.users.add(userEntryCompleter.index, id);
+ userEntry.clear();
+ userEntryCompleter.visible = false;
+ }
- }
+ function onCountChanged() {
+ if (userCompleter.count > 0 && (userCompleter.currentIndex < 0 || userCompleter.currentIndex >= userCompleter.count))
+ userCompleter.currentIndex = 0;
- target: userCompleter
}
- delegate: RowLayout {
- //anchors { fill: parent; margins: 2 }
- id: row
+ target: userCompleter
+ }
+
+ delegate: RowLayout {
+ //anchors { fill: parent; margins: 2 }
+ id: row
- Avatar {
- id: avatar
+ Avatar {
+ id: avatar
- Layout.preferredHeight: Nheko.avatarSize / 2
- Layout.preferredWidth: Nheko.avatarSize / 2
- Layout.leftMargin: 2
- userid: model.mxid
- url: {
- if (model.isUser)
- return model.avatarUrl.replace("mxc://", "image://MxcImage/")
- else if (editingModel.adminLevel >= model.powerlevel)
- return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?" + Nheko.colors.buttonText;
- else if (editingModel.moderatorLevel >= model.powerlevel)
- return "image://colorimage/:/icons/icons/ui/ribbon.svg?" + Nheko.colors.buttonText;
- else
- return "image://colorimage/:/icons/icons/ui/person.svg?" + Nheko.colors.buttonText;
- }
- displayName: model.displayName
- enabled: false
+ Layout.preferredHeight: Nheko.avatarSize / 2
+ Layout.preferredWidth: Nheko.avatarSize / 2
+ Layout.leftMargin: 2
+ userid: model.mxid
+ url: {
+ if (model.isUser)
+ return model.avatarUrl.replace("mxc://", "image://MxcImage/")
+ else if (editingModel.adminLevel >= model.powerlevel)
+ return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?" + Nheko.colors.buttonText;
+ else if (editingModel.moderatorLevel >= model.powerlevel)
+ return "image://colorimage/:/icons/icons/ui/ribbon.svg?" + Nheko.colors.buttonText;
+ else
+ return "image://colorimage/:/icons/icons/ui/person.svg?" + Nheko.colors.buttonText;
}
- Column {
- Layout.fillWidth: true
+ displayName: model.displayName
+ enabled: false
+ }
+ Column {
+ Layout.fillWidth: true
- Text { visible: model.isUser; text: model.displayName; color: Nheko.colors.text}
- Text { visible: model.isUser; text: model.mxid; color: Nheko.colors.text}
- Text {
- visible: !model.isUser;
- text: {
- if (editingModel.adminLevel == model.powerlevel)
- return qsTr("Administrator (%1)").arg(model.powerlevel)
- else if (editingModel.moderatorLevel == model.powerlevel)
- return qsTr("Moderator (%1)").arg(model.powerlevel)
- else
- return qsTr("Custom (%1)").arg(model.powerlevel)
- }
- color: Nheko.colors.text
+ Text { visible: model.isUser; text: model.displayName; color: Nheko.colors.text}
+ Text { visible: model.isUser; text: model.mxid; color: Nheko.colors.text}
+ Text {
+ visible: !model.isUser;
+ text: {
+ if (editingModel.adminLevel == model.powerlevel)
+ return qsTr("Administrator (%1)").arg(model.powerlevel)
+ else if (editingModel.moderatorLevel == model.powerlevel)
+ return qsTr("Moderator (%1)").arg(model.powerlevel)
+ else
+ return qsTr("Custom (%1)").arg(model.powerlevel)
}
+ color: Nheko.colors.text
}
+ }
- ImageButton {
- Layout.alignment: Qt.AlignRight
- Layout.rightMargin: 2
- image: model.isUser ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg"
- visible: !model.isUser || model.removeable
- hoverEnabled: true
- ToolTip.visible: hovered
- ToolTip.text: model.isUser ? qsTr("Remove user") : qsTr("Add user")
- onClicked: {
- if (model.isUser) {
- editingModel.users.remove(index);
- } else {
- userEntryCompleter.y = offset
- userEntryCompleter.visible = true
- userEntryCompleter.index = index;
- userEntry.forceActiveFocus()
- }
+ ImageButton {
+ Layout.alignment: Qt.AlignRight
+ Layout.rightMargin: 2
+ image: model.isUser ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg"
+ visible: !model.isUser || model.removeable
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: model.isUser ? qsTr("Remove user") : qsTr("Add user")
+ onClicked: {
+ if (model.isUser) {
+ editingModel.users.remove(index);
+ } else {
+ userEntryCompleter.y = offset
+ userEntryCompleter.visible = true
+ userEntryCompleter.index = index;
+ userEntry.forceActiveFocus()
}
}
}
}
-
}
+
}
}
}
+ }
- footer: DialogButtonBox {
- id: dbb
+ footer: DialogButtonBox {
+ id: dbb
- standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
- onAccepted: {
- editingModel.commit();
- plEditorW.close();
- }
- onRejected: plEditorW.close();
+ standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
+ onAccepted: {
+ editingModel.commit();
+ plEditorW.close();
}
-
+ onRejected: plEditorW.close();
}
+
+}
diff --git a/src/PowerlevelsEditModels.cpp b/src/PowerlevelsEditModels.cpp
index 77262a20..cea35495 100644
--- a/src/PowerlevelsEditModels.cpp
+++ b/src/PowerlevelsEditModels.cpp
@@ -239,6 +239,7 @@ PowerlevelsTypeListModel::remove(int row)
return true;
}
+
void
PowerlevelsTypeListModel::add(int row, QString type)
{
@@ -261,6 +262,23 @@ PowerlevelsTypeListModel::add(int row, QString type)
endInsertRows();
}
+void
+PowerlevelsTypeListModel::addRole(int64_t role)
+{
+ for (int i = 0; i < types.size(); i++) {
+ if (types[i].pl < role) {
+ beginInsertRows(QModelIndex(), i, i);
+ types.insert(i, Entry{"", role});
+ endInsertRows();
+ return;
+ }
+ }
+
+ beginInsertRows(QModelIndex(), types.size(), types.size());
+ types.push_back(Entry{"", role});
+ endInsertRows();
+}
+
bool
PowerlevelsTypeListModel::move(int from, int to)
{
@@ -299,10 +317,19 @@ PowerlevelsTypeListModel::moveRows(const QModelIndex &,
auto pl = types.at(destinationChild > 0 ? destinationChild - 1 : 0).pl;
auto sourceItem = types.takeAt(sourceRow);
sourceItem.pl = pl;
+
+ auto movedType = sourceItem.type;
+
if (destinationChild < sourceRow)
types.insert(destinationChild, std::move(sourceItem));
else
types.insert(destinationChild - 1, std::move(sourceItem));
+
+ if (movedType == "m.room.power_levels")
+ emit adminLevelChanged();
+ else if (movedType == "redact")
+ emit moderatorLevelChanged();
+
return true;
}
@@ -454,6 +481,23 @@ PowerlevelsUserListModel::add(int row, QString user)
endInsertRows();
}
+void
+PowerlevelsUserListModel::addRole(int64_t role)
+{
+ for (int i = 0; i < users.size(); i++) {
+ if (users[i].pl < role) {
+ beginInsertRows(QModelIndex(), i, i);
+ users.insert(i, Entry{"", role});
+ endInsertRows();
+ return;
+ }
+ }
+
+ beginInsertRows(QModelIndex(), users.size(), users.size());
+ users.push_back(Entry{"", role});
+ endInsertRows();
+}
+
bool
PowerlevelsUserListModel::move(int from, int to)
{
@@ -492,10 +536,17 @@ PowerlevelsUserListModel::moveRows(const QModelIndex &,
auto pl = users.at(destinationChild > 0 ? destinationChild - 1 : 0).pl;
auto sourceItem = users.takeAt(sourceRow);
sourceItem.pl = pl;
+
+ auto movedType = sourceItem.mxid;
+
if (destinationChild < sourceRow)
users.insert(destinationChild, std::move(sourceItem));
else
users.insert(destinationChild - 1, std::move(sourceItem));
+
+ if (movedType == "default")
+ emit defaultUserLevelChanged();
+
return true;
}
@@ -508,7 +559,20 @@ PowerlevelEditingModels::PowerlevelEditingModels(QString room_id, QObject *paren
, types_(room_id.toStdString(), powerLevels_, this)
, users_(room_id.toStdString(), powerLevels_, this)
, room_id_(room_id.toStdString())
-{}
+{
+ connect(&types_,
+ &PowerlevelsTypeListModel::adminLevelChanged,
+ this,
+ &PowerlevelEditingModels::adminLevelChanged);
+ connect(&types_,
+ &PowerlevelsTypeListModel::moderatorLevelChanged,
+ this,
+ &PowerlevelEditingModels::moderatorLevelChanged);
+ connect(&users_,
+ &PowerlevelsUserListModel::defaultUserLevelChanged,
+ this,
+ &PowerlevelEditingModels::defaultUserLevelChanged);
+}
void
PowerlevelEditingModels::commit()
@@ -532,3 +596,14 @@ PowerlevelEditingModels::commit()
}
});
}
+
+void
+PowerlevelEditingModels::addRole(int pl)
+{
+ for (const auto &e : types_.types)
+ if (pl == int(e.pl))
+ return;
+
+ types_.addRole(pl);
+ users_.addRole(pl);
+}
diff --git a/src/PowerlevelsEditModels.h b/src/PowerlevelsEditModels.h
index 25ad6d5a..9aa955d2 100644
--- a/src/PowerlevelsEditModels.h
+++ b/src/PowerlevelsEditModels.h
@@ -15,6 +15,10 @@ class PowerlevelsTypeListModel : public QAbstractListModel
{
Q_OBJECT
+signals:
+ void adminLevelChanged();
+ void moderatorLevelChanged();
+
public:
enum Roles
{
@@ -36,6 +40,7 @@ public:
Q_INVOKABLE bool remove(int row);
Q_INVOKABLE bool move(int from, int to);
Q_INVOKABLE void add(int index, QString type);
+ void addRole(int64_t role);
bool moveRows(const QModelIndex &sourceParent,
int sourceRow,
@@ -50,7 +55,6 @@ public:
mtx::events::state::power_level_t eventsDefault();
mtx::events::state::power_level_t stateDefault();
-private:
struct Entry
{
~Entry() = default;
@@ -68,6 +72,9 @@ class PowerlevelsUserListModel : public QAbstractListModel
{
Q_OBJECT
+signals:
+ void defaultUserLevelChanged();
+
public:
enum Roles
{
@@ -91,6 +98,7 @@ public:
Q_INVOKABLE bool remove(int row);
Q_INVOKABLE bool move(int from, int to);
Q_INVOKABLE void add(int index, QString user);
+ void addRole(int64_t role);
bool moveRows(const QModelIndex &sourceParent,
int sourceRow,
@@ -101,7 +109,6 @@ public:
std::map<std::string, mtx::events::state::power_level_t, std::less<>> toUsers();
mtx::events::state::power_level_t usersDefault();
-private:
struct Entry
{
~Entry() = default;
@@ -121,8 +128,14 @@ class PowerlevelEditingModels : public QObject
Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT)
Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT)
- Q_PROPERTY(qlonglong adminLevel READ adminLevel CONSTANT)
- Q_PROPERTY(qlonglong moderatorLevel READ moderatorLevel CONSTANT)
+ Q_PROPERTY(qlonglong adminLevel READ adminLevel NOTIFY adminLevelChanged)
+ Q_PROPERTY(qlonglong moderatorLevel READ moderatorLevel NOTIFY moderatorLevelChanged)
+ Q_PROPERTY(qlonglong defaultUserLevel READ defaultUserLevel NOTIFY defaultUserLevelChanged)
+
+signals:
+ void adminLevelChanged();
+ void moderatorLevelChanged();
+ void defaultUserLevelChanged();
public:
explicit PowerlevelEditingModels(QString room_id, QObject *parent = nullptr);
@@ -134,8 +147,10 @@ public:
return powerLevels_.state_level(to_string(mtx::events::EventType::RoomPowerLevels));
}
qlonglong moderatorLevel() const { return powerLevels_.redact; }
+ qlonglong defaultUserLevel() const { return powerLevels_.users_default; }
Q_INVOKABLE void commit();
+ Q_INVOKABLE void addRole(int pl);
mtx::events::state::PowerLevels powerLevels_;
PowerlevelsTypeListModel types_;
|