WIP: Tabbed options interface

This commit is contained in:
Floris Bos 2023-09-22 23:51:36 +02:00
parent 4c71a2294e
commit 6eb358ed75
3 changed files with 343 additions and 313 deletions

View file

@ -5,20 +5,20 @@
import QtQuick 2.15
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
import QtQuick.Layouts 1.15
import QtQuick.Controls.Material 2.2
import QtQuick.Window 2.15
import "qmlcomponents"
Popup {
Window {
id: popup
//x: 62
x: (parent.width-width)/2
y: 10
//width: parent.width-125
width: popupbody.implicitWidth+60
height: parent.height-20
padding: 0
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
width: cl.implicitWidth+cl.spacing
minimumWidth: width
maximumWidth: width
minimumHeight: 125
height: Math.min(750, cl.implicitHeight)
title: qsTr("Advanced options")
property bool initialized: false
property bool hasSavedSettings: false
property string config
@ -29,57 +29,11 @@ Popup {
property string cloudinitwrite
property string cloudinitnetwork
// background of title
Rectangle {
color: "#f5f5f5"
anchors.right: parent.right
anchors.top: parent.top
height: 35
width: parent.width
}
// line under title
Rectangle {
color: "#afafaf"
width: parent.width
y: 35
implicitHeight: 1
}
Text {
id: msgx
text: "X"
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 25
anchors.topMargin: 10
font.family: roboto.name
font.bold: true
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
initialized = false
popup.close()
}
}
}
ColumnLayout {
id: cl
spacing: 20
anchors.fill: parent
Text {
id: popupheader
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.topMargin: 10
font.family: roboto.name
font.bold: true
text: qsTr("Advanced options")
}
ScrollView {
id: popupbody
font.family: roboto.name
@ -89,15 +43,13 @@ Popup {
Layout.leftMargin: 25
Layout.topMargin: 10
clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
//ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ColumnLayout {
GroupBox {
title: qsTr("Image customization options")
label: RowLayout {
RowLayout {
Label {
text: parent.parent.title
text: qsTr("Image customization options")
}
ComboBox {
id: comboSaveSettings
@ -111,7 +63,28 @@ Popup {
}
}
TabBar {
id: bar
Layout.fillWidth: true
TabButton {
text: qsTr("General")
}
TabButton {
text: qsTr("Services")
}
TabButton {
text: qsTr("Options")
}
}
GroupBox {
StackLayout {
width: parent.width
currentIndex: bar.currentIndex
ColumnLayout {
// General tab
spacing: -10
RowLayout {
@ -135,68 +108,7 @@ Popup {
color: chkHostname.checked ? "black" : "grey"
}
}
ImCheckBox {
id: chkSSH
text: qsTr("Enable SSH")
onCheckedChanged: {
if (checked) {
if (!radioPasswordAuthentication.checked && !radioPubKeyAuthentication.checked) {
radioPasswordAuthentication.checked = true
}
if (radioPasswordAuthentication.checked) {
chkSetUser.checked = true
if (!fieldUserPassword.length) {
fieldUserPassword.forceActiveFocus()
}
}
}
}
}
ColumnLayout {
enabled: chkSSH.checked
Layout.leftMargin: 40
spacing: -10
ImRadioButton {
id: radioPasswordAuthentication
text: qsTr("Use password authentication")
onCheckedChanged: {
if (checked) {
chkSetUser.checked = true
fieldUserPassword.forceActiveFocus()
}
}
}
ImRadioButton {
id: radioPubKeyAuthentication
text: qsTr("Allow public-key authentication only")
onCheckedChanged: {
if (checked) {
if (chkSetUser.checked && fieldUserName.text == "pi" && fieldUserPassword.text.length == 0) {
chkSetUser.checked = false
}
fieldPublicKey.forceActiveFocus()
}
}
}
GridLayout {
Layout.leftMargin: 40
columns: 2
columnSpacing: 10
rowSpacing: -5
enabled: radioPubKeyAuthentication.checked
Text {
text: qsTr("Set authorized_keys for '%1':").arg(fieldUserName.text)
color: parent.enabled ? "black" : "grey"
textFormat: Text.PlainText
}
TextField {
id: fieldPublicKey
Layout.minimumWidth: 200
}
}
}
ImCheckBox {
id: chkSetUser
@ -362,13 +274,88 @@ Popup {
}
}
}
}
GroupBox {
title: qsTr("Persistent settings")
Layout.fillWidth: true
ColumnLayout {
// Remote access tab
spacing: -10
ImCheckBox {
id: chkSSH
text: qsTr("Enable SSH")
onCheckedChanged: {
if (checked) {
if (!radioPasswordAuthentication.checked && !radioPubKeyAuthentication.checked) {
radioPasswordAuthentication.checked = true
}
if (radioPasswordAuthentication.checked) {
chkSetUser.checked = true
if (!fieldUserPassword.length) {
fieldUserPassword.forceActiveFocus()
}
}
}
}
}
ColumnLayout {
enabled: chkSSH.checked
Layout.leftMargin: 40
spacing: -10
ImRadioButton {
id: radioPasswordAuthentication
text: qsTr("Use password authentication")
onCheckedChanged: {
if (checked) {
chkSetUser.checked = true
//fieldUserPassword.forceActiveFocus()
}
}
}
ImRadioButton {
id: radioPubKeyAuthentication
text: qsTr("Allow public-key authentication only")
onCheckedChanged: {
if (checked) {
if (chkSetUser.checked && fieldUserName.text == "pi" && fieldUserPassword.text.length == 0) {
chkSetUser.checked = false
}
fieldPublicKey.forceActiveFocus()
}
}
}
GridLayout {
Layout.leftMargin: 40
columns: 1
columnSpacing: 10
rowSpacing: -5
enabled: radioPubKeyAuthentication.checked
Text {
text: qsTr("Set authorized_keys for '%1':").arg(fieldUserName.text)
color: parent.enabled ? "black" : "grey"
textFormat: Text.PlainText
}
TextArea {
id: fieldPublicKey
wrapMode: TextEdit.WrapAnywhere
Layout.minimumWidth: 400
}
ImButton {
text: qsTr("RUN SSH-KEYGEN")
enabled: imageWriter.hasSshKeyGen() && !imageWriter.hasPubKey()
onClicked: {
enabled = false
imageWriter.generatePubKey()
fieldPublicKey.text = imageWriter.getDefaultPubKey()
}
}
}
}
}
ColumnLayout {
// Options tab
spacing: -10
ImCheckBox {
@ -387,6 +374,7 @@ Popup {
}
}
}
}
RowLayout {
Layout.alignment: Qt.AlignCenter | Qt.AlignBottom
@ -400,12 +388,14 @@ Popup {
{
fieldUserPassword.indicateError = true
fieldUserPassword.forceActiveFocus()
bar.currentIndex = 0
return
}
if (chkSetUser.checked && fieldUserName.text.length == 0)
{
fieldUserName.indicateError = true
fieldUserName.forceActiveFocus()
bar.currentIndex = 0
return
}
@ -423,6 +413,7 @@ Popup {
}
if (fieldWifiSSID.indicateError || fieldWifiPassword.indicateError)
{
bar.currentIndex = 0
return
}
}
@ -559,7 +550,9 @@ Popup {
initialize()
}
open()
//open()
show()
raise()
popupbody.forceActiveFocus()
}

View file

@ -790,10 +790,22 @@ QByteArray ImageWriter::getUsbSourceOSlist()
#endif
}
QString ImageWriter::_pubKeyFileName()
{
return QDir::homePath()+"/.ssh/id_rsa.pub";
}
QString ImageWriter::_privKeyFileName()
{
QString fn = _pubKeyFileName();
fn.chop(4);
return fn;
}
QString ImageWriter::getDefaultPubKey()
{
QByteArray pubkey;
QFile pubfile(QDir::homePath()+"/.ssh/id_rsa.pub");
QFile pubfile(_pubKeyFileName());
if (pubfile.exists() && pubfile.open(QFile::ReadOnly))
{
@ -804,6 +816,26 @@ QString ImageWriter::getDefaultPubKey()
return pubkey;
}
bool ImageWriter::hasPubKey()
{
return QFile::exists(_pubKeyFileName());
}
bool ImageWriter::hasSshKeyGen()
{
return true;
}
void ImageWriter::generatePubKey()
{
if (!hasPubKey() && !QFile::exists(_privKeyFileName()))
{
QStringList args;
args << "-t" << "rsa" << "-f" << _privKeyFileName() << "-N" << "";
QProcess::execute("ssh-keygen", args);
}
}
QString ImageWriter::getTimezone()
{
return QTimeZone::systemTimeZoneId();

View file

@ -98,6 +98,9 @@ public:
/* Functions to collect information from computer running imager to make image customization easier */
Q_INVOKABLE QString getDefaultPubKey();
Q_INVOKABLE bool hasPubKey();
Q_INVOKABLE bool hasSshKeyGen();
Q_INVOKABLE void generatePubKey();
Q_INVOKABLE QString getTimezone();
Q_INVOKABLE QStringList getTimezoneList();
Q_INVOKABLE QStringList getCountryList();
@ -178,6 +181,8 @@ protected:
#endif
void _parseCompressedFile();
QString _pubKeyFileName();
QString _privKeyFileName();
};
#endif // IMAGEWRITER_H