Skip to content

Commit

Permalink
qml, control: new IPAddressValueInput
Browse files Browse the repository at this point in the history
Adding a new improved ValueInput control to handle both IP address and port values
combined in the same field with the correct visual formatting (255.255.255.255:65535).

In this iteration, validation for this control is implemented using both a function
within the control itself focused solely on ensuring correct formatting and a simple regex
validator for the valid input characters.
Future versions will see integration with network model classes, enabling parsing of IP
addresses and ports and additional checks, such as those outlined in doc/p2p-bad-ports.md.
  • Loading branch information
pablomartin4btc committed Mar 26, 2024
1 parent a7e1b25 commit 7893dfb
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/qml/bitcoin_qml.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<file>controls/Header.qml</file>
<file>controls/Icon.qml</file>
<file>controls/InformationPage.qml</file>
<file>controls/IPAddressValueInput.qml</file>
<file>controls/NavButton.qml</file>
<file>controls/PageIndicator.qml</file>
<file>controls/NavigationBar.qml</file>
Expand Down
18 changes: 10 additions & 8 deletions src/qml/components/ProxySettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ ColumnLayout {
actionItem: ValueInput {
parentState: defaultProxy.state
description: "127.0.0.1:9050"
onEditingFinished: {
defaultProxy.forceActiveFocus()
}
activeFocusOnTab: true
}
onClicked: {
loadedItem.filled = true
loadedItem.forceActiveFocus()
}
onClicked: loadedItem.forceActiveFocus()
}
Separator { Layout.fillWidth: true }
Header {
Expand Down Expand Up @@ -93,11 +94,12 @@ ColumnLayout {
actionItem: ValueInput {
parentState: torProxy.state
description: "127.0.0.1:9050"
onEditingFinished: {
torProxy.forceActiveFocus()
}
activeFocusOnTab: true
}
onClicked: {
loadedItem.filled = true
loadedItem.forceActiveFocus()
}
onClicked: loadedItem.forceActiveFocus()
}
Separator { Layout.fillWidth: true }
}
83 changes: 83 additions & 0 deletions src/qml/controls/IPAddressValueInput.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2024 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

import QtQuick 2.15
import QtQuick.Controls 2.15

TextInput {
id: root
required property string parentState
property string description: ""
property bool filled: false
property int descriptionSize: 18
property color textColor: root.filled ? Theme.color.neutral9 : Theme.color.neutral5
// Expose a property to indicate validity, initial value will be true (no error message displayed)
// if both properties errortText and description are set
property bool validInput: description!=="" && errorText!==""
enabled: true
state: root.parentState
validator: RegExpValidator { regExp: /[0-9.:]*/ } // Allow only digits, dots, and colons

maximumLength: 21

states: [
State {
name: "ACTIVE"
PropertyChanges { target: root; textColor: Theme.color.orange }
},
State {
name: "HOVER"
PropertyChanges {
target: root
textColor: root.filled ? Theme.color.orangeLight1 : Theme.color.neutral5
}
},
State {
name: "DISABLED"
PropertyChanges {
target: root
enabled: false
textColor: Theme.color.neutral4
}
}
]

font.family: "Inter"
font.styleName: "Regular"
font.pixelSize: root.descriptionSize
color: root.textColor
text: root.description
horizontalAlignment: Text.AlignRight
wrapMode: Text.WordWrap

Behavior on color {
ColorAnimation { duration: 150 }
}

function isValidIPPort(input)
{
var parts = input.split(":");
if (parts.length !== 2) return false;
if (parts[1].length === 0) return false; // port part is empty
var ipAddress = parts[0];
var ipAddressParts = ipAddress.split(".");
if (ipAddressParts.length !== 4) return false;
for (var i = 0; (i < ipAddressParts.length); i++) {
if (ipAddressParts[i].length === 0) return false; // ip group number part is empty
if (parseInt(ipAddressParts[i]) > 255) return false;
}
var port = parseInt(parts[1]);
if (port < 1 || port > 65535) return false;
return true;
}

// Connections element to ensure validation on editing finished
Connections {
target: root
onEditingFinished: {
// Validate the input whenever editing is finished
validInput = isValidIPPort(root.text);
}
}
}

0 comments on commit 7893dfb

Please sign in to comment.