diff --git a/src/server/views/AddUpdateUser.qml b/src/server/views/AddUpdateUser.qml index 9fa15372d..c7b389506 100644 --- a/src/server/views/AddUpdateUser.qml +++ b/src/server/views/AddUpdateUser.qml @@ -1,225 +1,320 @@ /* GCompris - AddUpdateUser.qml * * Copyright (C) 2017 Johnny Jazeix * * Authors: * Johnny Jazeix * * 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 . */ import QtQuick 2.1 import GCompris 1.0 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.0 import "../../core" import "qrc:/gcompris/src/core/core.js" as Core Rectangle { id: addUpdateRectangle anchors.fill: parent color: "white" signal addUsers(ListModel model) ListModel { id: userToUpdateModel } TableView { id: users width: parent.width - 50 height: parent.height - (bar.height * 2) + property string name: ""; + property string dateOfBirth: "" + property string password: ""; + + function save() { + console.log("saving user") + + if(name != "" && dateOfBirth != "") { + + console.log("name of the user: ", name, "date of birth of the user: ", dateOfBirth, "password : ", password) + + userToUpdateModel.append({ + "name": name, + "dateOfBirth": dateOfBirth, + "password": password + }) + name="" + dateOfBirth="" + password="" + console.log("total number of users: ", userToUpdateModel.count) + } + + } + model: userToUpdateModel selectionMode: SelectionMode.MultiSelection rowDelegate: Rectangle { height: 50 width: childrenRect.width SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } color: { var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base return styleData.selected ? myPalette.highlight : baseColor } } TableViewColumn { role: "name" title: qsTr("Name") + width: 100 + } TableViewColumn { role: "dateOfBirth" title: qsTr("Birth year") + width: 100 } TableViewColumn { id: passwordColumn role: "password" + width: 100 title: qsTr("Password") + delegate: Item { - width: passwordColumn.height - height: 50 // same as rowDelegate + id: passwordColumn + width: passwordColumn.width // same as rowDelegate Item { id: passwordField anchors.fill: parent + Component.onCompleted: { + users.password = passwordImage.source.toString() + } + MouseArea { anchors.fill: parent onClicked: { passwordImage.visible = !passwordImage.visible } } - Text { + GCText { id: passwordText visible: !passwordImage.visible verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit text: modelData ? modelData.password : "" } Image { id: passwordImage source: "qrc:/gcompris/src/activities/sudoku/sudoku.svg" sourceSize.height: 50 } } } } + TableViewColumn { + id: saveDelete + resizable: true + title: qsTr("Save or Delete") + signal forceFocus() + width: users.width/3 + delegate: Item { + id: itemDel + width: 100 + height: 40 + anchors.topMargin: 20 + Rectangle { + id: save + width: 100 + height: 40 + color: "black" + anchors.rightMargin: 10 + GCText { + anchors.centerIn: parent + fontSize: tinySize + color: "white" + text: qsTr("Save") + } + MouseArea { + id: saveMouseArea + anchors.fill: parent + onClicked: { + saveDelete.forceFocus() + users.save() + } + } + + } + Rectangle { + id: deleteUser + width: 100 + height: 40 + anchors.leftMargin: 10 + anchors.left: save.right + color: "black" + GCText { + anchors.centerIn: parent + fontSize: tinySize + color: "white" + text: qsTr("Delete") + } + MouseArea { + anchors.fill: parent + onClicked: { + userToUpdateModel.remove(styleData.row) + users.selection.clear(); + } + } + } + } + + } itemDelegate: Rectangle { + id: rect SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } color: { var baseColor = styleData.row % 2 == 1 ? myPalette.alternateBase : myPalette.base return styleData.selected ? myPalette.highlight : baseColor } - Text { - anchors { - verticalCenter: parent.verticalCenter - left: parent.left - } - color: "black" - text: styleData.value - } MouseArea { id: cellMouseArea anchors.fill: parent onClicked: { // Column index are zero based if(styleData.column === 0 || styleData.column === 1) { loader.visible = true loader.item.forceActiveFocus() } } } Loader { id: loader anchors { verticalCenter: parent.verticalCenter left: parent.left } height: parent.height width: parent.width - visible: false + visible: true sourceComponent: visible ? input : undefined + Connections { + target: saveDelete + // forcing the focus triggers 'editingFinised' signal of TextField. + onForceFocus: { + loader.item.forceActiveFocus() + } + + } Component { id: input TextField { anchors.fill: parent + visible: true text: "" onAccepted: { loader.visible = false } - onActiveFocusChanged: { - if (!activeFocus) { - switch(styleData.column) { - case 0: - userToUpdateModel.get(styleData.row).name = text + onEditingFinished: { + switch(styleData.column) { + case 0: { + if(text != "") + users.name = text + break; + } + case 1: { + if(text != "") + users.dateOfBirth = text break; - case 1: - userToUpdateModel.get(styleData.row).age = text } - loader.visible = false } } } } } } } Column { id: addRemoveColumn anchors.left: users.right anchors.bottom: users.bottom spacing: 5 width: 50 Button { id: removeSelectedUsers text: qsTr("-") enabled: users.selection.count != 0 width: parent.width style: GCButtonStyle {} onClicked: { var idToRemove = [] users.selection.forEach(function(rowIndex) { idToRemove.push(rowIndex) }); for(var i = idToRemove.length-1 ; i >= 0 ; -- i) { userToUpdateModel.remove(idToRemove[i]); } users.selection.clear() } } Button { id: addUsersButton text: qsTr("+") width: parent.width style: GCButtonStyle {} onClicked: { - userToUpdateModel.append({"name": "", "dateOfBirth": "", "password": ""}) +// add empty user at first index. The first user is always going to be empty + userToUpdateModel.insert(0, {"name": "", "dateOfBirth": "", "password": ""}) } } } Grid { rows: 1 anchors.top: users.bottom spacing: 5 Button { id: createButton text: qsTr("Create") style: GCButtonStyle {} onClicked: { addUsers(userToUpdateModel) addUpdateRectangle.visible = false } } Button { id: cancelUserButton text: qsTr("Cancel") style: GCButtonStyle {} onClicked: { addUpdateRectangle.visible = false userToUpdateModel.clear() } } } } diff --git a/src/server/views/UsersManagement.qml b/src/server/views/UsersManagement.qml index 50bde348b..8207c95d7 100644 --- a/src/server/views/UsersManagement.qml +++ b/src/server/views/UsersManagement.qml @@ -1,320 +1,322 @@ /* GCompris - UsersManagement.qml * * Copyright (C) 2017 Johnny Jazeix * * Authors: * Johnny Jazeix * * 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 . */ import QtQuick 2.6 import GCompris 1.0 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import "../../core" import "qrc:/gcompris/src/core/core.js" as Core ActivityBase { id: activity activityInfo: QtObject { property bool demo: false } pageComponent: Item { id: mainItem anchors.fill: parent ListView { id: groupList anchors.left: parent.left model: MessageHandler.groups width: parent.width / 5 height: parent.height - (bar.height * 2) headerPositioning: ListView.OverlayHeader header: Rectangle { z: groupList.z + 1 width: groupList.width height: 50 radius: 10 color: "white" border.color: "black" border.width: 3 GCText { id: contactInfo text: qsTr("Groups") anchors.fill: parent width: parent.width height: parent.height fontSizeMode: Text.Fit color: "black" } } footerPositioning: ListView.OverlayFooter footer: Flow { z: groupList.z + 1 width: groupList.width height: 50 Button { // todo put images? Add, Clone, Edit, Delete text: qsTr("+") onClicked: addGroupTable.createGroup() } Button { text: qsTr("Edit") onClicked: { print(groupList.model); // crash without print addGroupTable.editGroup(groupList.model[groupList.currentIndex].name) } } Button { text: qsTr("Clone") onClicked: { print(groupList.model); // crash without print addGroupTable.cloneGroup(groupList.model[groupList.currentIndex].name) } } Button { text: qsTr("-") onClicked: { Core.showMessageDialog( main, qsTr("Delete group %1?").arg(groupList.model[groupList.currentIndex].name), qsTr("Yes"), function() { MessageHandler.deleteGroup(groupList.model[groupList.currentIndex].name) }, qsTr("No"), null, function() { } ); } } } delegate: Rectangle { id: wrapper z: groupList.z width: groupList.width height: 50 radius: 10 color: wrapper.ListView.isCurrentItem ? "black" : "white" GCText { id: contactInfo text: modelData.name color: wrapper.ListView.isCurrentItem ? "white" : "black" } MouseArea { anchors.fill: parent onClicked: groupList.currentIndex = index } } } AddUpdateGroup { id: addGroupTable visible: false anchors.fill: parent z: users.z + 1 onAddGroup: { print(newGroup.name, newGroup.users) MessageHandler.createGroup(newGroup.name, "", newGroup.users) } onUpdateGroup: { print(group.oldName, group.name, group.users) MessageHandler.updateGroup(group.oldName, group.name, "", group.users) } } Rectangle { id: userText anchors.left: groupList.right width: users.width height: 50 radius: 10 color: "white" border.color: "black" border.width: 3 GCText { id: contactInfo text: qsTr("Users") anchors.fill: parent width: parent.width height: parent.height fontSizeMode: Text.Fit color: "black" } } TableView { id: users anchors.left: groupList.right anchors.right: parent.right anchors.top: userText.bottom height: parent.height - (bar.height * 2) - userText.height model: MessageHandler.users rowDelegate: Rectangle { height: 50 width: childrenRect.width SystemPalette { id: myPalette; colorGroup: SystemPalette.Active } color: { var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base return styleData.selected ? myPalette.highlight : baseColor } } TableViewColumn { role: "name" title: qsTr("Name") width: users.width / 5 } TableViewColumn { role: "dateOfBirth" title: qsTr("Birth year") width: parent.width / 5 } TableViewColumn { id: passwordColumn role: "password" title: qsTr("Password") width: users.width / 5 delegate: Item { // todo Put it in a separate file width: passwordColumn.height height: 50 // same as rowDelegate Button { id: passwordButton text: qsTr("Show password") //style: GCButtonStyle {} onClicked: { passwordButton.visible = false } } Item { id: passwordField anchors.fill: parent visible: !passwordButton.visible MouseArea { anchors.fill: parent onClicked: { passwordImage.visible = !passwordImage.visible } } Text { id: passwordText visible: !passwordImage.visible verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit text: modelData ? modelData.password : "" } Image { id: passwordImage source: "qrc:/gcompris/src/activities/sudoku/sudoku.svg" sourceSize.height: 50 } } } } TableViewColumn { id: groupsColumn role: "groups" title: qsTr("Groups") width: 2 * users.width / 5 delegate: Text { verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit text: { // todo clean up... MessageHandler.groups.filter(function(elem) { return elem.users.filter(function(elem) { return modelData && (elem.name == modelData.name) }).length != 0 }).map(function(elem) { return elem.name; }).join(", ") } } } } Grid { rows: 1 anchors.bottom: bar.top spacing: 5 Button { id: createUserButton text: qsTr("Add user(s)") style: GCButtonStyle {} onClicked: { addUserTable.visible = true } } Button { id: updateUserButton enabled: users.selection.count != 0 text: qsTr("Edit user") style: GCButtonStyle {} onClicked: { users.selection.forEach(function(rowIndex) { print("edit user " + users.model[rowIndex].name) }); //addUserTable.visible = true } } Button { id: deleteUserButton enabled: users.selection.count != 0 text: qsTr("Delete selected") style: GCButtonStyle {} onClicked: { Core.showMessageDialog( main, qsTr("Confirm the deletion of selected users"), qsTr("Yes"), function() { var namesToRemove = []; users.selection.forEach(function(rowIndex) { namesToRemove.push(users.model[rowIndex].name) }); for(var name in namesToRemove) { print("Removing", namesToRemove[name]) MessageHandler.deleteUser(namesToRemove[name]) } users.selection.clear() }, qsTr("No"), null, function() { } ); } } } AddUpdateUser { id: addUserTable visible: false onAddUsers: { for(var i = model.count-1 ; i >= 0 ; -- i) { var userToAdd = model.get(i) - MessageHandler.createUser(userToAdd.name, userToAdd.dateOfBirth, userToAdd.password) + if(userToAdd.name != "" && userToAdd.dateOfBirth != "" && userToAdd.password != "") { + MessageHandler.createUser(userToAdd.name, userToAdd.dateOfBirth, userToAdd.password) + } } } } Bar { id: bar content: BarEnumContent { value: home } onHomeClicked: activity.home() } } }