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 2.15
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.15
import QtQuick.Controls.Material 2.2 import QtQuick.Controls.Material 2.2
import QtQuick.Window 2.15
import "qmlcomponents" import "qmlcomponents"
Popup { Window {
id: popup id: popup
//x: 62 width: cl.implicitWidth+cl.spacing
x: (parent.width-width)/2 minimumWidth: width
y: 10 maximumWidth: width
//width: parent.width-125 minimumHeight: 125
width: popupbody.implicitWidth+60 height: Math.min(750, cl.implicitHeight)
height: parent.height-20 title: qsTr("Advanced options")
padding: 0
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
property bool initialized: false property bool initialized: false
property bool hasSavedSettings: false property bool hasSavedSettings: false
property string config property string config
@ -29,57 +29,11 @@ Popup {
property string cloudinitwrite property string cloudinitwrite
property string cloudinitnetwork 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 { ColumnLayout {
id: cl
spacing: 20 spacing: 20
anchors.fill: parent 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 { ScrollView {
id: popupbody id: popupbody
font.family: roboto.name font.family: roboto.name
@ -89,15 +43,13 @@ Popup {
Layout.leftMargin: 25 Layout.leftMargin: 25
Layout.topMargin: 10 Layout.topMargin: 10
clip: true clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn //ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ColumnLayout { ColumnLayout {
GroupBox { RowLayout {
title: qsTr("Image customization options")
label: RowLayout {
Label { Label {
text: parent.parent.title text: qsTr("Image customization options")
} }
ComboBox { ComboBox {
id: comboSaveSettings 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 { ColumnLayout {
// General tab
spacing: -10 spacing: -10
RowLayout { RowLayout {
@ -135,68 +108,7 @@ Popup {
color: chkHostname.checked ? "black" : "grey" 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 { ImCheckBox {
id: chkSetUser id: chkSetUser
@ -362,13 +274,88 @@ Popup {
} }
} }
} }
}
GroupBox {
title: qsTr("Persistent settings")
Layout.fillWidth: true
ColumnLayout { 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 spacing: -10
ImCheckBox { ImCheckBox {
@ -387,6 +374,7 @@ Popup {
} }
} }
} }
}
RowLayout { RowLayout {
Layout.alignment: Qt.AlignCenter | Qt.AlignBottom Layout.alignment: Qt.AlignCenter | Qt.AlignBottom
@ -400,12 +388,14 @@ Popup {
{ {
fieldUserPassword.indicateError = true fieldUserPassword.indicateError = true
fieldUserPassword.forceActiveFocus() fieldUserPassword.forceActiveFocus()
bar.currentIndex = 0
return return
} }
if (chkSetUser.checked && fieldUserName.text.length == 0) if (chkSetUser.checked && fieldUserName.text.length == 0)
{ {
fieldUserName.indicateError = true fieldUserName.indicateError = true
fieldUserName.forceActiveFocus() fieldUserName.forceActiveFocus()
bar.currentIndex = 0
return return
} }
@ -423,6 +413,7 @@ Popup {
} }
if (fieldWifiSSID.indicateError || fieldWifiPassword.indicateError) if (fieldWifiSSID.indicateError || fieldWifiPassword.indicateError)
{ {
bar.currentIndex = 0
return return
} }
} }
@ -559,7 +550,9 @@ Popup {
initialize() initialize()
} }
open() //open()
show()
raise()
popupbody.forceActiveFocus() popupbody.forceActiveFocus()
} }

View file

@ -790,10 +790,22 @@ QByteArray ImageWriter::getUsbSourceOSlist()
#endif #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() QString ImageWriter::getDefaultPubKey()
{ {
QByteArray pubkey; QByteArray pubkey;
QFile pubfile(QDir::homePath()+"/.ssh/id_rsa.pub"); QFile pubfile(_pubKeyFileName());
if (pubfile.exists() && pubfile.open(QFile::ReadOnly)) if (pubfile.exists() && pubfile.open(QFile::ReadOnly))
{ {
@ -804,6 +816,26 @@ QString ImageWriter::getDefaultPubKey()
return pubkey; 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() QString ImageWriter::getTimezone()
{ {
return QTimeZone::systemTimeZoneId(); return QTimeZone::systemTimeZoneId();

View file

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